def _read_emoji_test_data(data_string):
    """Parse the emoji-test.txt data.  This has names of proposed emoji that are
    not yet in the full Unicode data file.  Returns a list of tuples of
    sequence, group, subgroup, name.

    The data is a string."""
    line_re = re.compile(
        r"([0-9a-fA-F ]+)\s*;\s*(%s)\s*#\s*(?:[^\s]+)\s+(.*)\s*"
        % "|".join(_EMOJI_QUAL_TYPES)
    )
    result = []
    GROUP_PREFIX = "# group: "
    SUBGROUP_PREFIX = "# subgroup: "
    group = None
    subgroup = None
    for line in data_string.splitlines():
        line = line.strip()
        if not line:
            continue

        if line[0] == "#":
            if line.startswith(GROUP_PREFIX):
                group = line[len(GROUP_PREFIX) :].strip().encode("ascii")
                subgroup = None
            elif line.startswith(SUBGROUP_PREFIX):
                subgroup = line[len(SUBGROUP_PREFIX) :].strip().encode("ascii")
            continue

        m = line_re.match(line)
        if not m:
            raise ValueError('Did not match "%s" in emoji-test.txt' % line)
        if m.group(2) not in ["component", "fully-qualified"]:
            # We only want component and fully-qualified sequences, as those are
            # 'canonical'.  'minimally-qualified' apparently just leave off the
            # FEOF emoji presentation tag, we already assume these.
            # Information for the unqualified sequences should be
            # redundant.  At the moment we don't verify this so if the file
            # changes we won't catch that.
            continue
        seq = tuple(int(s, 16) for s in m.group(1).split())
        name = m.group(3).strip()
        if not (group and subgroup):
            raise Exception(
                "sequence %s missing group or subgroup" % seq_to_string(seq)
            )
        result.append((seq, group, subgroup, name))

    return result