import sys
import unittest

from tf.fabric import Fabric

# LOAD THE TEST CORPUS

TF = Fabric('tf')
api = TF.load('sign name')
F = api.F
S = api.S

# MAKE CUSTOM SETS OF NODES

Sign = set(range(1, F.otype.maxSlot + 1))
Node = set(range(1, F.otype.maxNode + 1))

sets = dict(Sign=Sign, Node=Node)


# RUN A QUERY, OPTIONALLY WITH CUSTOM SETS

def query(template, sets=None):

  return (
      tuple(S.search(template))
      if sets is None else
      tuple(S.search(template, sets=sets))
  )


# DEFINE THE TESTS

relationKey = {
    '=': 'equal',
    '#': 'unequal',
    '<': 'canonicalBefore',
    '>': 'canonicalAfter',
    '==': 'sameSlots',
    '&&': 'overlap',
    '##': 'differentSlots',
    '||': 'disjointSlots',
    '[[': 'has',
    ']]': 'in',
    '<<': 'slotBefore',
    '>>': 'slotAfter',
    '=:': 'startSame',
    '=0:': 'startSame0',
    '=1:': 'startSame1',
    '=2:': 'startSame2',
    ':=': 'endSame',
    ':0=': 'endSame0',
    ':1=': 'endSame1',
    ':2=': 'endSame2',
    '::': 'sameBoundary',
    ':0:': 'sameBoundary0',
    ':1:': 'sameBoundary1',
    ':2:': 'sameBoundary2',
    '<:': 'adjacentBefore',
    '<0:': 'adjacentBefore0',
    '<1:': 'adjacentBefore1',
    '<2:': 'adjacentBefore2',
    ':>': 'adjacentAfter',
    ':0>': 'adjacentAfter0',
    ':1>': 'adjacentAfter1',
    ':2>': 'adjacentAfter2',
    '.namesign=namepart.': 'featureEqualSP',
    '.namesign=namesign.': 'featureEqualSS',
    '.namesign#namesign.': 'featureUnequalSS',
    '.namesign.': 'featureEqualSS',
    '.number.': 'featureEqualN',
    '.number#number.': 'featureUnEqualN',
    '.number>number.': 'featureGreaterN',
    '.number<number.': 'featureLesserN',
    '.namesign~(^[sp]{2}-)|(-[sp]{2}$)~namepart.': 'featureFuzzySP1',
    '.namesign~(^[sp]{2}-)|(-[sp]{2}$)~namesign.': 'featureFuzzySS1',
    '.namepart~(^[sp]{2}-)|(-[sp]{2}$)~namepart.': 'featureFuzzyPP1',
    '.namesign~([sp]-)|(-[sp])~namepart.': 'featureFuzzySP2',
    '.namesign~([sp]-)|(-[sp])~namesign.': 'featureFuzzySS2',
    '.namepart~([sp]-)|(-[sp])~namepart.': 'featureFuzzyPP2',
}

# DEFINE THE PARAMETERS FOR EACH TEST

comparisons = {
    '=': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', False),
        ('part', 's1', 'part', 's1', True),
        ('part', 's1', 'part', 's2', False),
        ('part', 'lower', 'part', 'lower', True),
        ('part', 'lower', 'part', 'upper', False),
    ),
    '#': (
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', True),
        ('part', 's1', 'part', 's1', False),
        ('part', 's1', 'part', 's2', True),
        ('part', 'lower', 'part', 'lower', False),
        ('part', 'lower', 'part', 'upper', True),
    ),
    '<': (
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'b', 'sign', 'a', False),
        ('sign', 'd', 'sign', 'g', True),
        ('sign', 'g', 'sign', 'd', False),
        ('part', 'lower', 'part', 'upper', True),
        ('part', 'upper', 'part', 'lower', False),
        ('part', 'big', 'part', 'small1', True),
        ('part', 'big', 'part', 'small2', True),
        ('part', 'big', 'part', 'small3', True),
        ('part', 'big', 'part', 'small4', True),
        ('part', 'small1', 'part', 'big', False),
        ('part', 'small2', 'part', 'big', False),
        ('part', 'small3', 'part', 'big', False),
        ('part', 'small4', 'part', 'big', False),
        ('part', 'small5', 'part', 'big', False),
        ('part', 'small6', 'part', 'big', False),
        ('part', 'small7', 'part', 'big', False),
        ('part', 'small8', 'part', 'big', True),
        ('sign', 'a', 'part', 'big', True),
        ('sign', 'b', 'part', 'big', True),
        ('sign', 'c', 'part', 'big', False),
        ('sign', 'd', 'part', 'big', False),
        ('sign', 'i', 'part', 'big', False),
        ('sign', 'j', 'part', 'big', False),
    ),
    '>': (
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'b', 'sign', 'a', True),
        ('sign', 'd', 'sign', 'g', False),
        ('sign', 'g', 'sign', 'd', True),
        ('part', 'lower', 'part', 'upper', False),
        ('part', 'upper', 'part', 'lower', True),
        ('part', 'big', 'part', 'small1', False),
        ('part', 'big', 'part', 'small2', False),
        ('part', 'big', 'part', 'small3', False),
        ('part', 'big', 'part', 'small4', False),
        ('part', 'small1', 'part', 'big', True),
        ('part', 'small2', 'part', 'big', True),
        ('part', 'small3', 'part', 'big', True),
        ('part', 'small4', 'part', 'big', True),
        ('part', 'small5', 'part', 'big', True),
        ('part', 'small6', 'part', 'big', True),
        ('part', 'small7', 'part', 'big', True),
        ('part', 'small8', 'part', 'big', False),
        ('sign', 'a', 'part', 'big', False),
        ('sign', 'b', 'part', 'big', False),
        ('sign', 'c', 'part', 'big', True),
        ('sign', 'd', 'part', 'big', True),
        ('sign', 'i', 'part', 'big', True),
        ('sign', 'j', 'part', 'big', True),
    ),
    '==': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', False),
        ('part', 'john', 'part', 'mary', True),
        ('part', 'john', 'part', 'small4', False),
        ('sign', 'a', 'part', 's1', True),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 'small1', 'part', 'big', False),
        ('part', 'big', 'part', 'small1', False),
    ),
    '&&': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', False),
        ('part', 'john', 'part', 'mary', True),
        ('part', 'john', 'part', 'john', True),
        ('part', 'john', 'part', 'small4', True),
        ('part', 'lower', 'part', 'upper', False),
        ('part', 'odd', 'part', 'even', False),
        ('sign', 'c', 'part', 'odd', True),
        ('sign', 'd', 'part', 'odd', False),
        ('sign', 'c', 'part', 'even', False),
        ('sign', 'd', 'part', 'even', True),
    ),
    '##': (
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', True),
        ('part', 'john', 'part', 'mary', False),
        ('part', 'john', 'part', 'john', False),
        ('part', 'john', 'part', 'big', True),
        ('sign', 'c', 'part', 'odd', True),
        ('sign', 'd', 'part', 'odd', True),
        ('part', 'even', 'sign', 'c', True),
        ('part', 'even', 'sign', 'd', True),
    ),
    '||': (
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', True),
        ('part', 'john', 'part', 'mary', False),
        ('part', 'john', 'part', 'john', False),
        ('part', 'john', 'part', 'small4', False),
        ('part', 'lower', 'part', 'upper', True),
        ('part', 'odd', 'part', 'even', True),
        ('sign', 'c', 'part', 'odd', False),
        ('sign', 'd', 'part', 'odd', True),
        ('sign', 'c', 'part', 'even', True),
        ('sign', 'd', 'part', 'even', False),
    ),
    '[[': (
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', False),
        ('part', 's1', 'sign', 'a', True),
        ('sign', 'a', 'part', 's1', False),
        ('part', 's1', 'part', 's1', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 'ss1', 'part', 's1', True),
        ('part', 'john', 'part', 'john', False),
        ('part', 'john', 'part', 'mary', True),
        ('part', 'mary', 'part', 'john', True),
        ('part', 'big', 'part', 'small1', True),
        ('part', 'big', 'part', 'small2', True),
        ('part', 'big', 'part', 'small3', True),
        ('part', 'big', 'part', 'small4', True),
        ('part', 'big', 'part', 'small5', False),
        ('part', 'big', 'part', 'small6', False),
        ('part', 'big', 'part', 'small7', False),
        ('part', 'big', 'part', 'small8', False),
        ('part', 'small1', 'part', 'big', False),
        ('part', 'small2', 'part', 'big', False),
        ('part', 'small3', 'part', 'big', False),
        ('part', 'small4', 'part', 'big', False),
        ('part', 'small5', 'part', 'big', False),
        ('part', 'small6', 'part', 'big', False),
        ('part', 'small7', 'part', 'big', False),
        ('part', 'small8', 'part', 'big', False),
    ),
    ']]': (
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', False),
        ('part', 's1', 'sign', 'a', False),
        ('sign', 'a', 'part', 's1', True),
        ('part', 's1', 'part', 's1', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 'ss1', 'part', 's1', True),
        ('part', 'john', 'part', 'john', False),
        ('part', 'john', 'part', 'mary', True),
        ('part', 'mary', 'part', 'john', True),
        ('part', 'big', 'part', 'small1', False),
        ('part', 'big', 'part', 'small2', False),
        ('part', 'big', 'part', 'small3', False),
        ('part', 'big', 'part', 'small4', False),
        ('part', 'big', 'part', 'small5', False),
        ('part', 'big', 'part', 'small6', False),
        ('part', 'big', 'part', 'small7', False),
        ('part', 'big', 'part', 'small8', False),
        ('part', 'small1', 'part', 'big', True),
        ('part', 'small2', 'part', 'big', True),
        ('part', 'small3', 'part', 'big', True),
        ('part', 'small4', 'part', 'big', True),
        ('part', 'small5', 'part', 'big', False),
        ('part', 'small6', 'part', 'big', False),
        ('part', 'small7', 'part', 'big', False),
        ('part', 'small8', 'part', 'big', False),
    ),
    '<<': (
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'b', 'sign', 'a', False),
        ('sign', 'c', 'sign', 'g', True),
        ('sign', 'g', 'sign', 'c', False),
        ('sign', 'c', 'part', 's2', False),
        ('sign', 'c', 'part', 's3', False),
        ('sign', 'c', 'part', 's4', True),
        ('part', 's2', 'sign', 'c', True),
        ('part', 's3', 'sign', 'c', False),
        ('part', 's4', 'sign', 'c', False),
        ('part', 's4', 'part', 's3', False),
        ('part', 's4', 'part', 's4', False),
        ('part', 's4', 'part', 's5', True),
        ('part', 's3', 'part', 's4', True),
        ('part', 's5', 'part', 's4', False),
        ('part', 's2', 'part', 'big', True),
        ('part', 's3', 'part', 'big', False),
        ('part', 's4', 'part', 'big', False),
        ('part', 'big', 'part', 's2', False),
        ('part', 'big', 'part', 's3', False),
        ('part', 'big', 'part', 's4', False),
        ('part', 'lower', 'part', 'upper', True),
        ('part', 'upper', 'part', 'lower', False),
        ('part', 'odd', 'part', 'even', False),
        ('part', 'even', 'part', 'odd', False),
    ),
    '>>': (
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'b', 'sign', 'a', True),
        ('sign', 'c', 'sign', 'g', False),
        ('sign', 'g', 'sign', 'c', True),
        ('sign', 'c', 'part', 's2', True),
        ('sign', 'c', 'part', 's3', False),
        ('sign', 'c', 'part', 's4', False),
        ('part', 's2', 'sign', 'c', False),
        ('part', 's3', 'sign', 'c', False),
        ('part', 's4', 'sign', 'c', True),
        ('part', 's4', 'part', 's3', True),
        ('part', 's4', 'part', 's4', False),
        ('part', 's4', 'part', 's5', False),
        ('part', 's3', 'part', 's4', False),
        ('part', 's5', 'part', 's4', True),
        ('part', 's2', 'part', 'big', False),
        ('part', 's3', 'part', 'big', False),
        ('part', 's4', 'part', 'big', False),
        ('part', 'big', 'part', 's2', True),
        ('part', 'big', 'part', 's3', False),
        ('part', 'big', 'part', 's4', False),
        ('part', 'lower', 'part', 'upper', False),
        ('part', 'upper', 'part', 'lower', True),
        ('part', 'odd', 'part', 'even', False),
        ('part', 'even', 'part', 'odd', False),
    ),
    '=:': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', False),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', False),
        ('part', 's1', 'part', 'ss3', False),
        ('part', 's1', 'part', 'ss4', False),
        ('sign', 'a', 'part', 'odd', True),
        ('part', 'odd', 'sign', 'a', True),
        ('part', 's1', 'part', 'odd', True),
        ('part', 'd4', 'part', 't3', True),
        ('part', 'lower', 'part', 'odd', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', False),
        ('part', 'jim2', 'part', 'all', False),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', False),
    ),
    '=0:': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', False),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', False),
        ('part', 's1', 'part', 'ss3', False),
        ('part', 's1', 'part', 'ss4', False),
        ('sign', 'a', 'part', 'odd', True),
        ('part', 'odd', 'sign', 'a', True),
        ('part', 's1', 'part', 'odd', True),
        ('part', 'd4', 'part', 't3', True),
        ('part', 'lower', 'part', 'odd', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', False),
        ('part', 'jim2', 'part', 'all', False),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', False),
    ),
    '=1:': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', True),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', True),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', True),
        ('part', 's1', 'part', 'ss3', False),
        ('part', 's1', 'part', 'ss4', False),
        ('sign', 'a', 'part', 'odd', True),
        ('part', 'odd', 'sign', 'a', True),
        ('part', 's1', 'part', 'odd', True),
        ('part', 'd4', 'part', 't3', True),
        ('part', 'lower', 'part', 'odd', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', True),
        ('part', 'jim2', 'part', 'all', False),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', True),
    ),
    '=2:': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'a', 'sign', 'c', True),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', True),
        ('sign', 'a', 'part', 's3', True),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', True),
        ('part', 's1', 'sign', 'c', True),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', True),
        ('part', 's1', 'part', 'ss3', True),
        ('part', 's1', 'part', 'ss4', False),
        ('sign', 'a', 'part', 'odd', True),
        ('part', 'odd', 'sign', 'a', True),
        ('part', 's1', 'part', 'odd', True),
        ('part', 'd4', 'part', 't3', True),
        ('part', 'lower', 'part', 'odd', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', True),
        ('part', 'jim2', 'part', 'all', True),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', True),
    ),
    ':=': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', False),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', False),
        ('part', 's1', 'part', 'ss3', False),
        ('part', 's1', 'part', 'ss4', False),
        ('sign', 'i', 'part', 'odd', True),
        ('part', 'odd', 'sign', 'i', True),
        ('part', 's9', 'part', 'odd', True),
        ('part', 'd3', 'part', 't2', True),
        ('part', 'upper', 'part', 'even', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', False),
        ('part', 'jim2', 'part', 'all', False),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', False),
    ),
    ':0=': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', False),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', False),
        ('part', 's1', 'part', 'ss3', False),
        ('part', 's1', 'part', 'ss4', False),
        ('sign', 'i', 'part', 'odd', True),
        ('part', 'odd', 'sign', 'i', True),
        ('part', 's9', 'part', 'odd', True),
        ('part', 'd3', 'part', 't2', True),
        ('part', 'upper', 'part', 'even', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', False),
        ('part', 'jim2', 'part', 'all', False),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', False),
    ),
    ':1=': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', True),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', True),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', True),
        ('part', 's1', 'part', 'ss3', False),
        ('part', 's1', 'part', 'ss4', False),
        ('sign', 'i', 'part', 'odd', True),
        ('part', 'odd', 'sign', 'i', True),
        ('part', 's9', 'part', 'odd', True),
        ('part', 'd3', 'part', 't2', True),
        ('part', 'upper', 'part', 'even', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', True),
        ('part', 'jim2', 'part', 'all', False),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', True),
    ),
    ':2=': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'a', 'sign', 'c', True),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', True),
        ('sign', 'a', 'part', 's3', True),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', True),
        ('part', 's1', 'sign', 'c', True),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', True),
        ('part', 's1', 'part', 'ss3', True),
        ('part', 's1', 'part', 'ss4', False),
        ('sign', 'i', 'part', 'odd', True),
        ('part', 'odd', 'sign', 'i', True),
        ('part', 's9', 'part', 'odd', True),
        ('part', 'd3', 'part', 't2', True),
        ('part', 'upper', 'part', 'even', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', True),
        ('part', 'jim2', 'part', 'all', True),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', True),
    ),
    '::': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', False),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', False),
        ('part', 's1', 'part', 'ss3', False),
        ('part', 's1', 'part', 'ss4', False),
        ('part', 'odd', 'sign', 'a', False),
        ('part', 's1', 'part', 'odd', False),
        ('part', 'lower', 'part', 'odd', False),
        ('part', 'john', 'part', 'john', True),
        ('part', 'john', 'part', 'fred', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', False),
        ('part', 'jim2', 'part', 'all', False),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', False),
    ),
    ':0:': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', False),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', False),
        ('part', 's1', 'part', 'ss3', False),
        ('part', 's1', 'part', 'ss4', False),
        ('part', 'odd', 'sign', 'a', False),
        ('part', 's1', 'part', 'odd', False),
        ('part', 'lower', 'part', 'odd', False),
        ('part', 'john', 'part', 'john', True),
        ('part', 'john', 'part', 'fred', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', False),
        ('part', 'jim2', 'part', 'all', False),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', False),
    ),
    ':1:': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', True),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', True),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', True),
        ('part', 's1', 'part', 'ss3', False),
        ('part', 's1', 'part', 'ss4', False),
        ('part', 'odd', 'sign', 'a', False),
        ('part', 's1', 'part', 'odd', False),
        ('part', 'lower', 'part', 'odd', False),
        ('part', 'john', 'part', 'john', True),
        ('part', 'john', 'part', 'fred', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', True),
        ('part', 'jim2', 'part', 'all', False),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', True),
    ),
    ':2:': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'a', 'sign', 'c', True),
        ('sign', 'a', 'sign', 'd', False),
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'part', 's2', True),
        ('sign', 'a', 'part', 's3', True),
        ('sign', 'a', 'part', 's4', False),
        ('part', 's1', 'sign', 'a', True),
        ('part', 's1', 'sign', 'b', True),
        ('part', 's1', 'sign', 'c', True),
        ('part', 's1', 'sign', 'd', False),
        ('part', 's1', 'part', 'ss1', True),
        ('part', 's1', 'part', 'ss2', True),
        ('part', 's1', 'part', 'ss3', True),
        ('part', 's1', 'part', 'ss4', False),
        ('part', 'odd', 'sign', 'a', False),
        ('part', 's1', 'part', 'odd', False),
        ('part', 'lower', 'part', 'odd', False),
        ('part', 'john', 'part', 'john', True),
        ('part', 'john', 'part', 'fred', True),
        ('part', 'jim', 'part', 'all', True),
        ('part', 'jim1', 'part', 'all', True),
        ('part', 'jim2', 'part', 'all', True),
        ('part', 'jim3', 'part', 'all', False),
        ('part', 'jim1', 'part', 'jim2', True),
    ),
    '<:': (
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'b', 'sign', 'c', True),
        ('sign', 'c', 'sign', 'c', False),
        ('sign', 'd', 'sign', 'c', False),
        ('sign', 'e', 'sign', 'c', False),
        ('part', 's1', 'part', 's3', False),
        ('part', 's2', 'part', 's3', True),
        ('part', 's3', 'part', 's3', False),
        ('part', 's4', 'part', 's3', False),
        ('part', 's5', 'part', 's3', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'b', 'part', 's3', True),
        ('sign', 'c', 'part', 's3', False),
        ('sign', 'd', 'part', 's3', False),
        ('sign', 'e', 'part', 's3', False),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's2', 'sign', 'c', True),
        ('part', 's3', 'sign', 'c', False),
        ('part', 's4', 'sign', 'c', False),
        ('part', 's5', 'sign', 'c', False),
        ('part', 'lower', 'part', 'upper', True),
        ('part', 'upper', 'part', 'lower', False),
        ('part', 'd2', 'part', 'small2', True),
        ('part', 'small2', 'part', 'd2', False),
        ('part', 't3', 'part', 'small2', False),
        ('part', 'small2', 'part', 't3', True),
        ('part', 'tim', 'part', 'tom', True),
        ('part', 'tom', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom1n', False),
        ('part', 'tom1n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom1p', False),
        ('part', 'tom1p', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2n', False),
        ('part', 'tom2n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2p', False),
        ('part', 'tom2p', 'part', 'tim', False),
        ('part', 'timb', 'part', 'tomb', True),
        ('part', 'tomb', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb1n', False),
        ('part', 'tomb1n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb1p', False),
        ('part', 'tomb1p', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2n', False),
        ('part', 'tomb2n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2p', False),
        ('part', 'tomb2p', 'part', 'timb', False),
        ('part', 'time', 'part', 'tome', False),
        ('part', 'tome', 'part', 'time', True),
        ('part', 'time', 'part', 'tome1n', False),
        ('part', 'tome1n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome1p', False),
        ('part', 'tome1p', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2n', False),
        ('part', 'tome2n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2p', False),
        ('part', 'tome2p', 'part', 'time', False),
    ),
    '<0:': (
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'b', 'sign', 'c', True),
        ('sign', 'c', 'sign', 'c', False),
        ('sign', 'd', 'sign', 'c', False),
        ('sign', 'e', 'sign', 'c', False),
        ('part', 's1', 'part', 's3', False),
        ('part', 's2', 'part', 's3', True),
        ('part', 's3', 'part', 's3', False),
        ('part', 's4', 'part', 's3', False),
        ('part', 's5', 'part', 's3', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'b', 'part', 's3', True),
        ('sign', 'c', 'part', 's3', False),
        ('sign', 'd', 'part', 's3', False),
        ('sign', 'e', 'part', 's3', False),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's2', 'sign', 'c', True),
        ('part', 's3', 'sign', 'c', False),
        ('part', 's4', 'sign', 'c', False),
        ('part', 's5', 'sign', 'c', False),
        ('part', 'lower', 'part', 'upper', True),
        ('part', 'upper', 'part', 'lower', False),
        ('part', 'd2', 'part', 'small2', True),
        ('part', 'small2', 'part', 'd2', False),
        ('part', 't3', 'part', 'small2', False),
        ('part', 'small2', 'part', 't3', True),
        ('part', 'tim', 'part', 'tom', True),
        ('part', 'tom', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom1n', False),
        ('part', 'tom1n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom1p', False),
        ('part', 'tom1p', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2n', False),
        ('part', 'tom2n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2p', False),
        ('part', 'tom2p', 'part', 'tim', False),
        ('part', 'timb', 'part', 'tomb', True),
        ('part', 'tomb', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb1n', False),
        ('part', 'tomb1n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb1p', False),
        ('part', 'tomb1p', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2n', False),
        ('part', 'tomb2n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2p', False),
        ('part', 'tomb2p', 'part', 'timb', False),
        ('part', 'time', 'part', 'tome', False),
        ('part', 'tome', 'part', 'time', True),
        ('part', 'time', 'part', 'tome1n', False),
        ('part', 'tome1n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome1p', False),
        ('part', 'tome1p', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2n', False),
        ('part', 'tome2n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2p', False),
        ('part', 'tome2p', 'part', 'time', False),
    ),
    '<1:': (
        ('sign', 'a', 'sign', 'c', True),
        ('sign', 'b', 'sign', 'c', True),
        ('sign', 'c', 'sign', 'c', True),
        ('sign', 'd', 'sign', 'c', False),
        ('sign', 'e', 'sign', 'c', False),
        ('part', 's1', 'part', 's3', True),
        ('part', 's2', 'part', 's3', True),
        ('part', 's3', 'part', 's3', True),
        ('part', 's4', 'part', 's3', False),
        ('part', 's5', 'part', 's3', False),
        ('sign', 'a', 'part', 's3', True),
        ('sign', 'b', 'part', 's3', True),
        ('sign', 'c', 'part', 's3', True),
        ('sign', 'd', 'part', 's3', False),
        ('sign', 'e', 'part', 's3', False),
        ('part', 's1', 'sign', 'c', True),
        ('part', 's2', 'sign', 'c', True),
        ('part', 's3', 'sign', 'c', True),
        ('part', 's4', 'sign', 'c', False),
        ('part', 's5', 'sign', 'c', False),
        ('part', 'lower', 'part', 'upper', True),
        ('part', 'upper', 'part', 'lower', False),
        ('part', 'd2', 'part', 'small2', True),
        ('part', 'small2', 'part', 'd2', False),
        ('part', 't3', 'part', 'small2', False),
        ('part', 'small2', 'part', 't3', True),
        ('part', 'tim', 'part', 'tom', True),
        ('part', 'tom', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom1n', True),
        ('part', 'tom1n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom1p', True),
        ('part', 'tom1p', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2n', False),
        ('part', 'tom2n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2p', False),
        ('part', 'tom2p', 'part', 'tim', False),
        ('part', 'timb', 'part', 'tomb', True),
        ('part', 'tomb', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb1n', True),
        ('part', 'tomb1n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb1p', True),
        ('part', 'tomb1p', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2n', False),
        ('part', 'tomb2n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2p', False),
        ('part', 'tomb2p', 'part', 'timb', False),
        ('part', 'time', 'part', 'tome', False),
        ('part', 'tome', 'part', 'time', True),
        ('part', 'time', 'part', 'tome1n', False),
        ('part', 'tome1n', 'part', 'time', True),
        ('part', 'time', 'part', 'tome1p', False),
        ('part', 'tome1p', 'part', 'time', True),
        ('part', 'time', 'part', 'tome2n', False),
        ('part', 'tome2n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2p', False),
        ('part', 'tome2p', 'part', 'time', False),
    ),
    '<2:': (
        ('sign', 'a', 'sign', 'c', True),
        ('sign', 'b', 'sign', 'c', True),
        ('sign', 'c', 'sign', 'c', True),
        ('sign', 'd', 'sign', 'c', True),
        ('sign', 'e', 'sign', 'c', False),
        ('part', 's1', 'part', 's3', True),
        ('part', 's2', 'part', 's3', True),
        ('part', 's3', 'part', 's3', True),
        ('part', 's4', 'part', 's3', True),
        ('part', 's5', 'part', 's3', False),
        ('sign', 'a', 'part', 's3', True),
        ('sign', 'b', 'part', 's3', True),
        ('sign', 'c', 'part', 's3', True),
        ('sign', 'd', 'part', 's3', True),
        ('sign', 'e', 'part', 's3', False),
        ('part', 's1', 'sign', 'c', True),
        ('part', 's2', 'sign', 'c', True),
        ('part', 's3', 'sign', 'c', True),
        ('part', 's4', 'sign', 'c', True),
        ('part', 's5', 'sign', 'c', False),
        ('part', 'lower', 'part', 'upper', True),
        ('part', 'upper', 'part', 'lower', False),
        ('part', 'd2', 'part', 'small2', True),
        ('part', 'small2', 'part', 'd2', False),
        ('part', 't3', 'part', 'small2', False),
        ('part', 'small2', 'part', 't3', True),
        ('part', 'tim', 'part', 'tom', True),
        ('part', 'tom', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom1n', True),
        ('part', 'tom1n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom1p', True),
        ('part', 'tom1p', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2n', True),
        ('part', 'tom2n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2p', True),
        ('part', 'tom2p', 'part', 'tim', True),
        ('part', 'timb', 'part', 'tomb', True),
        ('part', 'tomb', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb1n', True),
        ('part', 'tomb1n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb1p', True),
        ('part', 'tomb1p', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2n', True),
        ('part', 'tomb2n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2p', True),
        ('part', 'tomb2p', 'part', 'timb', True),
        ('part', 'time', 'part', 'tome', False),
        ('part', 'tome', 'part', 'time', True),
        ('part', 'time', 'part', 'tome1n', False),
        ('part', 'tome1n', 'part', 'time', True),
        ('part', 'time', 'part', 'tome1p', False),
        ('part', 'tome1p', 'part', 'time', True),
        ('part', 'time', 'part', 'tome2n', True),
        ('part', 'tome2n', 'part', 'time', True),
        ('part', 'time', 'part', 'tome2p', False),
        ('part', 'tome2p', 'part', 'time', True),
    ),
    ':>': (
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'b', 'sign', 'c', False),
        ('sign', 'c', 'sign', 'c', False),
        ('sign', 'd', 'sign', 'c', True),
        ('sign', 'e', 'sign', 'c', False),
        ('part', 's1', 'part', 's3', False),
        ('part', 's2', 'part', 's3', False),
        ('part', 's3', 'part', 's3', False),
        ('part', 's4', 'part', 's3', True),
        ('part', 's5', 'part', 's3', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'b', 'part', 's3', False),
        ('sign', 'c', 'part', 's3', False),
        ('sign', 'd', 'part', 's3', True),
        ('sign', 'e', 'part', 's3', False),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's2', 'sign', 'c', False),
        ('part', 's3', 'sign', 'c', False),
        ('part', 's4', 'sign', 'c', True),
        ('part', 's5', 'sign', 'c', False),
        ('part', 'lower', 'part', 'upper', False),
        ('part', 'upper', 'part', 'lower', True),
        ('part', 'd2', 'part', 'small2', False),
        ('part', 'small2', 'part', 'd2', True),
        ('part', 't3', 'part', 'small2', True),
        ('part', 'small2', 'part', 't3', False),
        ('part', 'tim', 'part', 'tom', False),
        ('part', 'tom', 'part', 'tim', True),
        ('part', 'tim', 'part', 'tom1n', False),
        ('part', 'tom1n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom1p', False),
        ('part', 'tom1p', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2n', False),
        ('part', 'tom2n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2p', False),
        ('part', 'tom2p', 'part', 'tim', False),
        ('part', 'timb', 'part', 'tomb', False),
        ('part', 'tomb', 'part', 'timb', True),
        ('part', 'timb', 'part', 'tomb1n', False),
        ('part', 'tomb1n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb1p', False),
        ('part', 'tomb1p', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2n', False),
        ('part', 'tomb2n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2p', False),
        ('part', 'tomb2p', 'part', 'timb', False),
        ('part', 'time', 'part', 'tome', True),
        ('part', 'tome', 'part', 'time', False),
        ('part', 'time', 'part', 'tome1n', False),
        ('part', 'tome1n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome1p', False),
        ('part', 'tome1p', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2n', False),
        ('part', 'tome2n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2p', False),
        ('part', 'tome2p', 'part', 'time', False),
    ),
    ':0>': (
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'b', 'sign', 'c', False),
        ('sign', 'c', 'sign', 'c', False),
        ('sign', 'd', 'sign', 'c', True),
        ('sign', 'e', 'sign', 'c', False),
        ('part', 's1', 'part', 's3', False),
        ('part', 's2', 'part', 's3', False),
        ('part', 's3', 'part', 's3', False),
        ('part', 's4', 'part', 's3', True),
        ('part', 's5', 'part', 's3', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'b', 'part', 's3', False),
        ('sign', 'c', 'part', 's3', False),
        ('sign', 'd', 'part', 's3', True),
        ('sign', 'e', 'part', 's3', False),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's2', 'sign', 'c', False),
        ('part', 's3', 'sign', 'c', False),
        ('part', 's4', 'sign', 'c', True),
        ('part', 's5', 'sign', 'c', False),
        ('part', 'lower', 'part', 'upper', False),
        ('part', 'upper', 'part', 'lower', True),
        ('part', 'd2', 'part', 'small2', False),
        ('part', 'small2', 'part', 'd2', True),
        ('part', 't3', 'part', 'small2', True),
        ('part', 'small2', 'part', 't3', False),
        ('part', 'tim', 'part', 'tom', False),
        ('part', 'tom', 'part', 'tim', True),
        ('part', 'tim', 'part', 'tom1n', False),
        ('part', 'tom1n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom1p', False),
        ('part', 'tom1p', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2n', False),
        ('part', 'tom2n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2p', False),
        ('part', 'tom2p', 'part', 'tim', False),
        ('part', 'timb', 'part', 'tomb', False),
        ('part', 'tomb', 'part', 'timb', True),
        ('part', 'timb', 'part', 'tomb1n', False),
        ('part', 'tomb1n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb1p', False),
        ('part', 'tomb1p', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2n', False),
        ('part', 'tomb2n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2p', False),
        ('part', 'tomb2p', 'part', 'timb', False),
        ('part', 'time', 'part', 'tome', True),
        ('part', 'tome', 'part', 'time', False),
        ('part', 'time', 'part', 'tome1n', False),
        ('part', 'tome1n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome1p', False),
        ('part', 'tome1p', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2n', False),
        ('part', 'tome2n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2p', False),
        ('part', 'tome2p', 'part', 'time', False),
    ),
    ':1>': (
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'b', 'sign', 'c', False),
        ('sign', 'c', 'sign', 'c', True),
        ('sign', 'd', 'sign', 'c', True),
        ('sign', 'e', 'sign', 'c', True),
        ('part', 's1', 'part', 's3', False),
        ('part', 's2', 'part', 's3', False),
        ('part', 's3', 'part', 's3', True),
        ('part', 's4', 'part', 's3', True),
        ('part', 's5', 'part', 's3', True),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'b', 'part', 's3', False),
        ('sign', 'c', 'part', 's3', True),
        ('sign', 'd', 'part', 's3', True),
        ('sign', 'e', 'part', 's3', True),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's2', 'sign', 'c', False),
        ('part', 's3', 'sign', 'c', True),
        ('part', 's4', 'sign', 'c', True),
        ('part', 's5', 'sign', 'c', True),
        ('part', 'lower', 'part', 'upper', False),
        ('part', 'upper', 'part', 'lower', True),
        ('part', 'd2', 'part', 'small2', False),
        ('part', 'small2', 'part', 'd2', True),
        ('part', 't3', 'part', 'small2', True),
        ('part', 'small2', 'part', 't3', False),
        ('part', 'tim', 'part', 'tom', False),
        ('part', 'tom', 'part', 'tim', True),
        ('part', 'tim', 'part', 'tom1n', False),
        ('part', 'tom1n', 'part', 'tim', True),
        ('part', 'tim', 'part', 'tom1p', False),
        ('part', 'tom1p', 'part', 'tim', True),
        ('part', 'tim', 'part', 'tom2n', False),
        ('part', 'tom2n', 'part', 'tim', False),
        ('part', 'tim', 'part', 'tom2p', False),
        ('part', 'tom2p', 'part', 'tim', False),
        ('part', 'timb', 'part', 'tomb', False),
        ('part', 'tomb', 'part', 'timb', True),
        ('part', 'timb', 'part', 'tomb1n', False),
        ('part', 'tomb1n', 'part', 'timb', True),
        ('part', 'timb', 'part', 'tomb1p', False),
        ('part', 'tomb1p', 'part', 'timb', True),
        ('part', 'timb', 'part', 'tomb2n', False),
        ('part', 'tomb2n', 'part', 'timb', False),
        ('part', 'timb', 'part', 'tomb2p', False),
        ('part', 'tomb2p', 'part', 'timb', False),
        ('part', 'time', 'part', 'tome', True),
        ('part', 'tome', 'part', 'time', False),
        ('part', 'time', 'part', 'tome1n', True),
        ('part', 'tome1n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome1p', True),
        ('part', 'tome1p', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2n', False),
        ('part', 'tome2n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2p', False),
        ('part', 'tome2p', 'part', 'time', False),
    ),
    ':2>': (
        ('sign', 'a', 'sign', 'c', False),
        ('sign', 'b', 'sign', 'c', True),
        ('sign', 'c', 'sign', 'c', True),
        ('sign', 'd', 'sign', 'c', True),
        ('sign', 'e', 'sign', 'c', True),
        ('part', 's1', 'part', 's3', False),
        ('part', 's2', 'part', 's3', True),
        ('part', 's3', 'part', 's3', True),
        ('part', 's4', 'part', 's3', True),
        ('part', 's5', 'part', 's3', True),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'b', 'part', 's3', True),
        ('sign', 'c', 'part', 's3', True),
        ('sign', 'd', 'part', 's3', True),
        ('sign', 'e', 'part', 's3', True),
        ('part', 's1', 'sign', 'c', False),
        ('part', 's2', 'sign', 'c', True),
        ('part', 's3', 'sign', 'c', True),
        ('part', 's4', 'sign', 'c', True),
        ('part', 's5', 'sign', 'c', True),
        ('part', 'lower', 'part', 'upper', False),
        ('part', 'upper', 'part', 'lower', True),
        ('part', 'd2', 'part', 'small2', False),
        ('part', 'small2', 'part', 'd2', True),
        ('part', 't3', 'part', 'small2', True),
        ('part', 'small2', 'part', 't3', False),
        ('part', 'tim', 'part', 'tom', False),
        ('part', 'tom', 'part', 'tim', True),
        ('part', 'tim', 'part', 'tom1n', False),
        ('part', 'tom1n', 'part', 'tim', True),
        ('part', 'tim', 'part', 'tom1p', False),
        ('part', 'tom1p', 'part', 'tim', True),
        ('part', 'tim', 'part', 'tom2n', False),
        ('part', 'tom2n', 'part', 'tim', True),
        ('part', 'tim', 'part', 'tom2p', True),
        ('part', 'tom2p', 'part', 'tim', True),
        ('part', 'timb', 'part', 'tomb', False),
        ('part', 'tomb', 'part', 'timb', True),
        ('part', 'timb', 'part', 'tomb1n', False),
        ('part', 'tomb1n', 'part', 'timb', True),
        ('part', 'timb', 'part', 'tomb1p', False),
        ('part', 'tomb1p', 'part', 'timb', True),
        ('part', 'timb', 'part', 'tomb2n', False),
        ('part', 'tomb2n', 'part', 'timb', True),
        ('part', 'timb', 'part', 'tomb2p', True),
        ('part', 'tomb2p', 'part', 'timb', True),
        ('part', 'time', 'part', 'tome', True),
        ('part', 'tome', 'part', 'time', False),
        ('part', 'time', 'part', 'tome1n', True),
        ('part', 'tome1n', 'part', 'time', False),
        ('part', 'time', 'part', 'tome1p', True),
        ('part', 'tome1p', 'part', 'time', False),
        ('part', 'time', 'part', 'tome2n', True),
        ('part', 'tome2n', 'part', 'time', True),
        ('part', 'time', 'part', 'tome2p', True),
        ('part', 'tome2p', 'part', 'time', False),
    ),
    '.namesign.': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'b', 'sign', 'a', False),
        ('sign', 'j', 'sign', 'j', False),
    ),
    '.namesign=namesign.': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'b', 'sign', 'a', False),
        ('sign', 'j', 'sign', 'j', False),
    ),
    '.namesign=namepart.': (
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'b', 'part', 's1', False),
        ('part', 's1', 'sign', 'a', False),
    ),
    '.number.': (
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'b', 'part', 's1', False),
        ('sign', 'b', 'part', 's2', True),
    ),
    '.namesign#namesign.': (
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'b', 'sign', 'a', True),
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'j', 'sign', 'j', True),
    ),
    '.number#number.': (
        ('sign', 'a', 'part', 's1', False),
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'j', 'sign', 'j', True),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'b', 'part', 's1', True),
        ('sign', 'b', 'part', 's2', False),
    ),
    '.number>number.': (
        ('sign', 'a', 'part', 's1', False),
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'b', 'sign', 'a', True),
        ('sign', 'b', 'part', 's2', False),
        ('sign', 'b', 'part', 's1', True),
        ('sign', 'j', 'sign', 'j', False),
        ('sign', 'j', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'j', False),
    ),
    '.number<number.': (
        ('sign', 'a', 'part', 's1', False),
        ('sign', 'a', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'b', 'sign', 'a', False),
        ('part', 's2', 'sign', 'b', False),
        ('part', 's1', 'sign', 'b', True),
        ('sign', 'j', 'sign', 'j', False),
        ('sign', 'j', 'sign', 'a', False),
        ('sign', 'a', 'sign', 'j', False),
    ),
    '.namesign~(^[sp]{2}-)|(-[sp]{2}$)~namepart.': (
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'b', 'part', 's2', True),
        ('sign', 'a', 'part', 's2', True),
        ('sign', 'b', 'part', 's1', True),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'b', 'part', 's3', False),
        ('sign', 'c', 'part', 's3', True),
    ),
    '.namesign~(^[sp]{2}-)|(-[sp]{2}$)~namesign.': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'b', 'sign', 'b', True),
        ('sign', 'c', 'sign', 'c', True),
        ('sign', 'a', 'sign', 'b', True),
        ('sign', 'a', 'sign', 'c', False),
    ),
    '.namepart~(^[sp]{2}-)|(-[sp]{2}$)~namepart.': (
        ('part', 's1', 'part', 's1', True),
        ('part', 's2', 'part', 's2', True),
        ('part', 's3', 'part', 's3', True),
        ('part', 's1', 'part', 's2', True),
        ('part', 's1', 'part', 's3', False),
    ),
    '.namesign~([sp]-)|(-[sp])~namepart.': (
        ('sign', 'a', 'part', 's1', True),
        ('sign', 'b', 'part', 's2', False),
        ('sign', 'a', 'part', 's2', False),
        ('sign', 'b', 'part', 's1', False),
        ('sign', 'a', 'part', 's3', False),
        ('sign', 'b', 'part', 's3', False),
        ('sign', 'c', 'part', 's3', False),
    ),
    '.namesign~([sp]-)|(-[sp])~namesign.': (
        ('sign', 'a', 'sign', 'a', True),
        ('sign', 'b', 'sign', 'b', True),
        ('sign', 'c', 'sign', 'c', True),
        ('sign', 'a', 'sign', 'b', False),
        ('sign', 'a', 'sign', 'c', False),
    ),
    '.namepart~([sp]-)|(-[sp])~namepart.': (
        ('part', 's1', 'part', 's1', True),
        ('part', 's2', 'part', 's2', True),
        ('part', 's3', 'part', 's3', True),
        ('part', 's1', 'part', 's2', False),
        ('part', 's1', 'part', 's3', False),
    ),
}


# BUILD THE TEST CLASS

def makeTests():

  # The central tester: run a query and check the result

  def basicRel(self, type1, name1, type2, name2, answer):
    '''
    Given the test parameters, build a query and run it.
    Depending on the node types involved, build additional
    queries with custom sets and run them.
    All queries should have the same result, given the parameters.
    That result is either the empty tuple or a singleton tuple.
    The expected answer states that whether the result is the singleton tuple.
    '''

    rel = self.rel
    template = f'''
{type1} name={name1}
{rel} {type2} name={name2}
'''
    hasResult = query(template) != ()
    self.assertions += 1
    self.assertTrue(hasResult if answer else not hasResult, msg=template)

    tp1s = ('Node', 'Sign') if type1 == 'sign' else ('Node',)
    tp2s = ('Node', 'Sign') if type2 == 'sign' else ('Node',)
    for tp1 in tp1s:
      for tp2 in tp2s:
        template = f'''
{tp1} name={name1}
{rel} {tp2} name={name2}
'''
        hasResult = query(template, sets=sets) != ()
        with self.subTest(msg=template):
          self.assertions += 1
          self.assertTrue(hasResult if answer else not hasResult)

  def makeTest(relSym, params):
    '''
    Given a relation operator symbol and a sequence of parameters for the
    basic tester, define a function that executes a corresponding seuqence
    of tests
    '''

    def xx(obj):
      obj.rel = relSym
      for values in params:
        obj.basicRel(*values)
    return xx

  # Compose a dictionary of test functions

  tests = {}
  for (relSym, params) in comparisons.items():
    testName = f'test_{relationKey[relSym]}'
    tests[testName] = makeTest(relSym, params)

  # See the unittest docs.
  # setUp and tearDown are used here for counting the assertions done.

  def setUp(self):
    self.assertions = 0

  def tearDown(self):
    global assertions
    assertions += self.assertions
    sys.stderr.write(
        f'assertions checked: {self.assertions:>3}'
        f' overall {assertions} ... '
    )

  # build a test class and add attributes to it,
  # in particular the tests in the dictionary just constructed

  testClass = type('relations', (unittest.TestCase,), {
      'longMessage': False,
      'basicRel': basicRel,
      'setUp': setUp,
      'tearDown': tearDown,
      **tests,
  })

  return testClass


if __name__ == '__main__':

  # define the test class and call it relations

  relations = makeTests()
  assertions = 0

  # perform tests

  unittest.main()
  sys.exit()

  # if you need to debug, do it here,
  # and comment out the line unittest.main() above

  print(query('''
part name=upper
:0= part name=even
'''))
