diff --git a/tests/generator/enum.py b/tests/generator/enum.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/enum.py
@@ -0,0 +1,39 @@
+import xcffib
+import struct
+import six
+_events = {}
+_errors = {}
+class DeviceUse:
+    IsXPointer = 0
+    IsXKeyboard = 1
+    IsXExtensionDevice = 2
+    IsXExtensionKeyboard = 3
+    IsXExtensionPointer = 4
+class EventMask:
+    NoEvent = 0
+    KeyPress = 1 << 0
+    KeyRelease = 1 << 1
+    ButtonPress = 1 << 2
+    ButtonRelease = 1 << 3
+    EnterWindow = 1 << 4
+    LeaveWindow = 1 << 5
+    PointerMotion = 1 << 6
+    PointerMotionHint = 1 << 7
+    Button1Motion = 1 << 8
+    Button2Motion = 1 << 9
+    Button3Motion = 1 << 10
+    Button4Motion = 1 << 11
+    Button5Motion = 1 << 12
+    ButtonMotion = 1 << 13
+    KeymapState = 1 << 14
+    Exposure = 1 << 15
+    VisibilityChange = 1 << 16
+    StructureNotify = 1 << 17
+    ResizeRedirect = 1 << 18
+    SubstructureNotify = 1 << 19
+    SubstructureRedirect = 1 << 20
+    FocusChange = 1 << 21
+    PropertyChange = 1 << 22
+    ColorMapChange = 1 << 23
+    OwnerGrabButton = 1 << 24
+xcffib._add_ext(key, enumExtension, _events, _errors)
diff --git a/tests/generator/enum.xml b/tests/generator/enum.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/enum.xml
@@ -0,0 +1,41 @@
+<!-- based on xproto -->
+<xcb header="enum">
+
+    <enum name="DeviceUse">
+        <item name="IsXPointer">           <value>0</value> </item>
+        <item name="IsXKeyboard">          <value>1</value> </item>
+        <item name="IsXExtensionDevice">   <value>2</value> </item>
+        <item name="IsXExtensionKeyboard"> <value>3</value> </item>
+        <item name="IsXExtensionPointer">  <value>4</value> </item>
+    </enum>
+
+  <enum name="EventMask">
+    <item name="NoEvent">           <value>0</value></item>
+    <item name="KeyPress">            <bit>0</bit></item>
+    <item name="KeyRelease">          <bit>1</bit></item>
+    <item name="ButtonPress">         <bit>2</bit></item>
+    <item name="ButtonRelease">       <bit>3</bit></item>
+    <item name="EnterWindow">         <bit>4</bit></item>
+    <item name="LeaveWindow">         <bit>5</bit></item>
+    <item name="PointerMotion">       <bit>6</bit></item>
+    <item name="PointerMotionHint">   <bit>7</bit></item>
+    <item name="Button1Motion">       <bit>8</bit></item>
+    <item name="Button2Motion">       <bit>9</bit></item>
+    <item name="Button3Motion">       <bit>10</bit></item>
+    <item name="Button4Motion">       <bit>11</bit></item>
+    <item name="Button5Motion">       <bit>12</bit></item>
+    <item name="ButtonMotion">        <bit>13</bit></item>
+    <item name="KeymapState">         <bit>14</bit></item>
+    <item name="Exposure">            <bit>15</bit></item>
+    <item name="VisibilityChange">    <bit>16</bit></item>
+    <item name="StructureNotify">     <bit>17</bit></item>
+    <item name="ResizeRedirect">      <bit>18</bit></item>
+    <item name="SubstructureNotify">  <bit>19</bit></item>
+    <item name="SubstructureRedirect"><bit>20</bit></item>
+    <item name="FocusChange">         <bit>21</bit></item>
+    <item name="PropertyChange">      <bit>22</bit></item>
+    <item name="ColorMapChange">      <bit>23</bit></item>
+    <item name="OwnerGrabButton">     <bit>24</bit></item>
+  </enum>
+
+</xcb>
diff --git a/tests/generator/error.py b/tests/generator/error.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/error.py
@@ -0,0 +1,22 @@
+import xcffib
+import struct
+import six
+MAJOR_VERSION = 2
+MINOR_VERSION = 2
+key = xcffib.ExtensionKey("ERROR")
+_events = {}
+_errors = {}
+class RequestError(xcffib.Error):
+    def __init__(self, unpacker):
+        xcffib.Error.__init__(self, unpacker)
+        base = unpacker.offset
+        self.bad_value, self.minor_opcode, self.major_opcode = unpacker.unpack("xx2xIHBx")
+        self.bufsize = unpacker.offset - base
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=B", 1))
+        buf.write(struct.pack("=x2xIHBx", self.bad_value, self.minor_opcode, self.major_opcode))
+        return buf.getvalue()
+BadRequest = RequestError
+_errors[1] = RequestError
+xcffib._add_ext(key, errorExtension, _events, _errors)
diff --git a/tests/generator/error.xml b/tests/generator/error.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/error.xml
@@ -0,0 +1,11 @@
+<!-- stolen from xv -->
+<xcb header="error" extension-xname="ERROR" extension-name="Error"
+    major-version="2" minor-version="2">
+
+  <error name="Request" number="1">
+    <field type="CARD32" name="bad_value" />
+    <field type="CARD16" name="minor_opcode" />
+    <field type="CARD8" name="major_opcode" />
+    <pad bytes="1" />
+  </error>
+</xcb>
diff --git a/tests/generator/event.py b/tests/generator/event.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/event.py
@@ -0,0 +1,24 @@
+import xcffib
+import struct
+import six
+MAJOR_VERSION = 1
+MINOR_VERSION = 4
+key = xcffib.ExtensionKey("EVENT")
+_events = {}
+_errors = {}
+class ScreenChangeNotifyEvent(xcffib.Event):
+    def __init__(self, unpacker):
+        xcffib.Event.__init__(self, unpacker)
+        base = unpacker.offset
+        self.rotation, self.timestamp, self.config_timestamp, self.root, self.request_window, self.sizeID, self.subpixel_order, self.width, self.height, self.mwidth, self.mheight = unpacker.unpack("xB2xIIIIHHHHHH")
+        self.bufsize = unpacker.offset - base
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=B", 0))
+        buf.write(struct.pack("=B2xIIIIHHHHHH", self.rotation, self.timestamp, self.config_timestamp, self.root, self.request_window, self.sizeID, self.subpixel_order, self.width, self.height, self.mwidth, self.mheight))
+        buf_len = len(buf.getvalue())
+        if buf_len < 32:
+            buf.write(struct.pack("x" * (32 - buf_len)))
+        return buf.getvalue()
+_events[0] = ScreenChangeNotifyEvent
+xcffib._add_ext(key, eventExtension, _events, _errors)
diff --git a/tests/generator/event.xml b/tests/generator/event.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/event.xml
@@ -0,0 +1,21 @@
+<!-- stolen from randr -->
+<xcb header="event" extension-xname="EVENT" extension-name="Event"
+    major-version="1" minor-version="4">
+
+  <xidtype name="WINDOW" />
+  <typedef oldname="CARD32" newname="TIMESTAMP" />
+
+  <event name="ScreenChangeNotify" number="0">
+    <field type="CARD8" name="rotation" mask="Rotation" />
+    <field type="TIMESTAMP" name="timestamp" />
+    <field type="TIMESTAMP" name="config_timestamp" />
+    <field type="WINDOW" name="root" />
+    <field type="WINDOW" name="request_window" />
+    <field type="CARD16" name="sizeID" />
+    <field type="CARD16" name="subpixel_order" enum="SubPixel" />
+    <field type="CARD16" name="width" />
+    <field type="CARD16" name="height" />
+    <field type="CARD16" name="mwidth" />
+    <field type="CARD16" name="mheight" />
+  </event>
+</xcb>
diff --git a/tests/generator/no_sequence.py b/tests/generator/no_sequence.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/no_sequence.py
@@ -0,0 +1,22 @@
+import xcffib
+import struct
+import six
+_events = {}
+_errors = {}
+class KeymapNotifyEvent(xcffib.Event):
+    def __init__(self, unpacker):
+        xcffib.Event.__init__(self, unpacker)
+        base = unpacker.offset
+        unpacker.unpack("x")
+        self.keys = xcffib.List(unpacker, "B", 31)
+        self.bufsize = unpacker.offset - base
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=B", 11))
+        buf.write(xcffib.pack_list(self.keys, "B"))
+        buf_len = len(buf.getvalue())
+        if buf_len < 32:
+            buf.write(struct.pack("x" * (32 - buf_len)))
+        return buf.getvalue()
+_events[11] = KeymapNotifyEvent
+xcffib._add_ext(key, no_sequenceExtension, _events, _errors)
diff --git a/tests/generator/no_sequence.xml b/tests/generator/no_sequence.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/no_sequence.xml
@@ -0,0 +1,5 @@
+<xcb header="no_sequence">
+  <event name="KeymapNotify" number="11" no-sequence-number="true">
+    <list type="CARD8" name="keys"><value>31</value></list>
+  </event>
+</xcb>
diff --git a/tests/generator/render_1.7.py b/tests/generator/render_1.7.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/render_1.7.py
@@ -0,0 +1,63 @@
+import xcffib
+import struct
+import six
+MAJOR_VERSION = 0
+MINOR_VERSION = 11
+key = xcffib.ExtensionKey("RENDER")
+_events = {}
+_errors = {}
+class PictOp:
+    Clear = 0
+    Src = 1
+    Dst = 2
+    Over = 3
+    OverReverse = 4
+    In = 5
+    InReverse = 6
+    Out = 7
+    OutReverse = 8
+    Atop = 9
+    AtopReverse = 10
+    Xor = 11
+    Add = 12
+    Saturate = 13
+    DisjointClear = 16
+    DisjointSrc = 17
+    DisjointDst = 18
+    DisjointOver = 19
+    DisjointOverReverse = 20
+    DisjointIn = 21
+    DisjointInReverse = 22
+    DisjointOut = 23
+    DisjointOutReverse = 24
+    DisjointAtop = 25
+    DisjointAtopReverse = 26
+    DisjointXor = 27
+    ConjointClear = 32
+    ConjointSrc = 33
+    ConjointDst = 34
+    ConjointOver = 35
+    ConjointOverReverse = 36
+    ConjointIn = 37
+    ConjointInReverse = 38
+    ConjointOut = 39
+    ConjointOutReverse = 40
+    ConjointAtop = 41
+    ConjointAtopReverse = 42
+    ConjointXor = 43
+    Multiply = 48
+    Screen = 49
+    Overlay = 50
+    Darken = 51
+    Lighten = 52
+    ColorDodge = 53
+    ColorBurn = 54
+    HardLight = 55
+    SoftLight = 56
+    Difference = 57
+    Exclusion = 58
+    HSLHue = 59
+    HSLSaturation = 60
+    HSLColor = 61
+    HSLLuminosity = 62
+xcffib._add_ext(key, render_1._7Extension, _events, _errors)
diff --git a/tests/generator/render_1.7.xml b/tests/generator/render_1.7.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/render_1.7.xml
@@ -0,0 +1,69 @@
+<!-- rendering of this enum in xcb-proto 1.7 is vastly more complicated than in
+     more modern versions of xcb-proto, but for completness we should render
+     this correctly as well -->
+<?xml version="1.0" encoding="utf-8"?>
+<xcb header="render_1.7" extension-xname="RENDER" extension-name="Render"
+    major-version="0" minor-version="11">
+
+  <!-- Disjoint* and Conjoint* are new in version 0.2 -->
+  <!-- PDF blend modes are new in version 0.11 -->
+  <enum name="PictOp">
+    <item name="Clear" />
+    <item name="Src" />
+    <item name="Dst" />
+    <item name="Over" />
+    <item name="OverReverse" />
+    <item name="In" />
+    <item name="InReverse" />
+    <item name="Out" />
+    <item name="OutReverse" />
+    <item name="Atop" />
+    <item name="AtopReverse" />
+    <item name="Xor" />
+    <item name="Add" />
+    <item name="Saturate" />
+    
+    <item name="DisjointClear"><value>16</value></item>
+    <item name="DisjointSrc" />
+    <item name="DisjointDst" />
+    <item name="DisjointOver" />
+    <item name="DisjointOverReverse" />
+    <item name="DisjointIn" />
+    <item name="DisjointInReverse" />
+    <item name="DisjointOut" />
+    <item name="DisjointOutReverse" />
+    <item name="DisjointAtop" />
+    <item name="DisjointAtopReverse" />
+    <item name="DisjointXor" />
+    
+    <item name="ConjointClear"><value>32</value></item>
+    <item name="ConjointSrc" />
+    <item name="ConjointDst" />
+    <item name="ConjointOver" />
+    <item name="ConjointOverReverse" />
+    <item name="ConjointIn" />
+    <item name="ConjointInReverse" />
+    <item name="ConjointOut" />
+    <item name="ConjointOutReverse" />
+    <item name="ConjointAtop" />
+    <item name="ConjointAtopReverse" />
+    <item name="ConjointXor" />
+
+    <!-- PDF blend modes are new in version 0.11 -->
+    <item name="Multiply"><value>48</value></item>
+    <item name="Screen" />
+    <item name="Overlay" />
+    <item name="Darken" />
+    <item name="Lighten" />
+    <item name="ColorDodge" />
+    <item name="ColorBurn" />
+    <item name="HardLight" />
+    <item name="SoftLight" />
+    <item name="Difference" />
+    <item name="Exclusion" />
+    <item name="HSLHue" />
+    <item name="HSLSaturation" />
+    <item name="HSLColor" />
+    <item name="HSLLuminosity" />
+  </enum>
+</xcb>
diff --git a/tests/generator/request.py b/tests/generator/request.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/request.py
@@ -0,0 +1,13 @@
+import xcffib
+import struct
+import six
+_events = {}
+_errors = {}
+class requestExtension(xcffib.Extension):
+    def CreateWindow(self, depth, wid, parent, x, y, width, height, border_width, _class, visual, value_mask, value_list, is_checked=False):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=xB2xIIhhHHHHI", depth, wid, parent, x, y, width, height, border_width, _class, visual))
+        buf.write(struct.pack("=I", value_mask))
+        buf.write(xcffib.pack_list(value_list, "I"))
+        return self.send_request(1, buf, is_checked=is_checked)
+xcffib._add_ext(key, requestExtension, _events, _errors)
diff --git a/tests/generator/request.xml b/tests/generator/request.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/request.xml
@@ -0,0 +1,90 @@
+<!-- based on xproto -->
+<xcb header="request">
+
+  <xidtype name="WINDOW" />
+  <typedef oldname="CARD32" newname="TIMESTAMP" />
+  <typedef oldname="CARD32" newname="VISUALID" />
+
+  <request name="CreateWindow" opcode="1">
+    <field type="CARD8" name="depth" />
+    <field type="WINDOW" name="wid" />
+    <field type="WINDOW" name="parent" />
+    <field type="INT16" name="x" />
+    <field type="INT16" name="y" />
+    <field type="CARD16" name="width" />
+    <field type="CARD16" name="height" />
+    <field type="CARD16" name="border_width" />
+    <field type="CARD16" name="class" enum="WindowClass" />
+    <field type="VISUALID" name="visual" />
+    <valueparam value-mask-type="CARD32"
+                value-mask-name="value_mask"
+                value-list-name="value_list" />
+    <doc>
+      <brief>Creates a window</brief>
+      <description><![CDATA[
+Creates an unmapped window as child of the specified `parent` window. A
+CreateNotify event will be generated. The new window is placed on top in the
+stacking order with respect to siblings.
+
+The coordinate system has the X axis horizontal and the Y axis vertical with
+the origin [0, 0] at the upper-left corner. Coordinates are integral, in terms
+of pixels, and coincide with pixel centers. Each window and pixmap has its own
+coordinate system. For a window, the origin is inside the border at the inside,
+upper-left corner.
+
+The created window is not yet displayed (mapped), call `xcb_map_window` to
+display it.
+
+The created window will initially use the same cursor as its parent.
+      ]]></description>
+      <field name="wid"><![CDATA[
+The ID with which you will refer to the new window, created by
+`xcb_generate_id`.
+      ]]></field>
+      <field name="depth"><![CDATA[
+Specifies the new window's depth.
+
+The special value `XCB_COPY_FROM_PARENT` means the depth is taken from the
+`parent` window.
+      ]]></field>
+      <field name="visual"><![CDATA[
+Specifies the id for the new window's visual.
+
+The special value `XCB_COPY_FROM_PARENT` means the visual is taken from the
+`parent` window.
+      ]]></field>
+      <field name="class"></field>
+      <field name="parent"><![CDATA[
+The parent window of the new window.
+      ]]></field>
+      <field name="border_width"><![CDATA[
+
+Must be zero if the `class` is `InputOnly` or a `xcb_match_error_t` occurs.
+      ]]></field>
+      <field name="x"><![CDATA[The X coordinate of the new window.]]></field>
+      <field name="y"><![CDATA[The Y coordinate of the new window.]]></field>
+      <field name="width"><![CDATA[The width of the new window.]]></field>
+      <field name="height"><![CDATA[The height of the new window.]]></field>
+      <error type="Colormap"><![CDATA[
+      ]]></error>
+      <error type="Match"><![CDATA[
+      ]]></error>
+      <error type="Cursor"><![CDATA[
+      ]]></error>
+      <error type="Pixmap"><![CDATA[
+      ]]></error>
+      <error type="Value"><![CDATA[
+      ]]></error>
+      <error type="Window"><![CDATA[
+      ]]></error>
+      <error type="Alloc"><![CDATA[
+The X server could not allocate the requested resources (no memory?).
+      ]]></error>
+      <see type="function" name="xcb_generate_id" />
+      <see type="request" name="MapWindow" />
+      <see type="event" name="CreateNotify" />
+    </doc>
+
+  </request>
+
+</xcb>
diff --git a/tests/generator/request_reply.py b/tests/generator/request_reply.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/request_reply.py
@@ -0,0 +1,32 @@
+import xcffib
+import struct
+import six
+_events = {}
+_errors = {}
+class STR(xcffib.Struct):
+    def __init__(self, unpacker):
+        xcffib.Struct.__init__(self, unpacker)
+        base = unpacker.offset
+        self.name_len, = unpacker.unpack("B")
+        self.name = xcffib.List(unpacker, "c", self.name_len)
+        self.bufsize = unpacker.offset - base
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=B", self.name_len))
+        buf.write(xcffib.pack_list(self.name, "c"))
+        return buf.getvalue()
+class ListExtensionsReply(xcffib.Reply):
+    def __init__(self, unpacker):
+        xcffib.Reply.__init__(self, unpacker)
+        base = unpacker.offset
+        self.names_len, = unpacker.unpack("xB2x4x24x")
+        self.names = xcffib.List(unpacker, STR, self.names_len)
+        self.bufsize = unpacker.offset - base
+class ListExtensionsCookie(xcffib.Cookie):
+    reply_type = ListExtensionsReply
+class request_replyExtension(xcffib.Extension):
+    def ListExtensions(self, is_checked=True):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=xx2x"))
+        return self.send_request(99, buf, ListExtensionsCookie, is_checked=is_checked)
+xcffib._add_ext(key, request_replyExtension, _events, _errors)
diff --git a/tests/generator/request_reply.xml b/tests/generator/request_reply.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/request_reply.xml
@@ -0,0 +1,21 @@
+<!-- based on xproto -->
+<xcb header="request_reply">
+
+  <struct name="STR">
+    <field type="CARD8" name="name_len" />
+    <list type="char" name="name">
+      <fieldref>name_len</fieldref>
+    </list>
+  </struct>
+
+  <request name="ListExtensions" opcode="99">
+    <reply>
+      <field type="CARD8" name="names_len" />
+      <pad bytes="24" />
+      <list type="STR" name="names">
+        <fieldref>names_len</fieldref>
+      </list>
+    </reply>
+  </request>
+
+</xcb>
diff --git a/tests/generator/struct.py b/tests/generator/struct.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/struct.py
@@ -0,0 +1,29 @@
+import xcffib
+import struct
+import six
+_events = {}
+_errors = {}
+class AxisInfo(xcffib.Struct):
+    def __init__(self, unpacker):
+        xcffib.Struct.__init__(self, unpacker)
+        base = unpacker.offset
+        self.resolution, self.minimum, self.maximum = unpacker.unpack("Iii")
+        self.bufsize = unpacker.offset - base
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=Iii", self.resolution, self.minimum, self.maximum))
+        return buf.getvalue()
+    fixed_size = 12
+class ValuatorInfo(xcffib.Struct):
+    def __init__(self, unpacker):
+        xcffib.Struct.__init__(self, unpacker)
+        base = unpacker.offset
+        self.class_id, self.len, self.axes_len, self.mode, self.motion_size = unpacker.unpack("BBBBI")
+        self.axes = xcffib.List(unpacker, AxisInfo, self.axes_len)
+        self.bufsize = unpacker.offset - base
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=BBBBI", self.class_id, self.len, self.axes_len, self.mode, self.motion_size))
+        buf.write(xcffib.pack_list(self.axes, AxisInfo))
+        return buf.getvalue()
+xcffib._add_ext(key, structExtension, _events, _errors)
diff --git a/tests/generator/struct.xml b/tests/generator/struct.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/struct.xml
@@ -0,0 +1,21 @@
+<!-- based on xproto -->
+<xcb header="struct">
+
+    <struct name="AxisInfo">
+        <field type="CARD32" name="resolution" />
+        <field type="INT32"  name="minimum" />
+        <field type="INT32"  name="maximum" />
+    </struct>
+
+    <struct name="ValuatorInfo">
+        <field type="CARD8"   name="class_id" enum="InputClass" />
+        <field type="CARD8"   name="len" />
+        <field type="CARD8"   name="axes_len" />
+        <field type="CARD8"   name="mode" enum="ValuatorMode" />
+        <field type="CARD32"  name="motion_size" />
+        <list type="AxisInfo" name="axes">
+            <fieldref>axes_len</fieldref>
+        </list>
+    </struct>
+
+</xcb>
diff --git a/tests/generator/type_pad.py b/tests/generator/type_pad.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/type_pad.py
@@ -0,0 +1,51 @@
+import xcffib
+import struct
+import six
+_events = {}
+_errors = {}
+class CHARINFO(xcffib.Struct):
+    def __init__(self, unpacker):
+        xcffib.Struct.__init__(self, unpacker)
+        base = unpacker.offset
+        self.left_side_bearing, self.right_side_bearing, self.character_width, self.ascent, self.descent, self.attributes = unpacker.unpack("hhhhhH")
+        self.bufsize = unpacker.offset - base
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=hhhhhH", self.left_side_bearing, self.right_side_bearing, self.character_width, self.ascent, self.descent, self.attributes))
+        return buf.getvalue()
+    fixed_size = 12
+class FONTPROP(xcffib.Struct):
+    def __init__(self, unpacker):
+        xcffib.Struct.__init__(self, unpacker)
+        base = unpacker.offset
+        self.name, self.value = unpacker.unpack("II")
+        self.bufsize = unpacker.offset - base
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=II", self.name, self.value))
+        return buf.getvalue()
+    fixed_size = 8
+class ListFontsWithInfoReply(xcffib.Reply):
+    def __init__(self, unpacker):
+        xcffib.Reply.__init__(self, unpacker)
+        base = unpacker.offset
+        self.name_len, = unpacker.unpack("xB2x4x")
+        self.min_bounds = CHARINFO(unpacker)
+        unpacker.unpack("4x")
+        unpacker.pad(CHARINFO)
+        self.max_bounds = CHARINFO(unpacker)
+        self.min_char_or_byte2, self.max_char_or_byte2, self.default_char, self.properties_len, self.draw_direction, self.min_byte1, self.max_byte1, self.all_chars_exist, self.font_ascent, self.font_descent, self.replies_hint = unpacker.unpack("4xHHHHBBBBhhI")
+        unpacker.pad(FONTPROP)
+        self.properties = xcffib.List(unpacker, FONTPROP, self.properties_len)
+        unpacker.pad("c")
+        self.name = xcffib.List(unpacker, "c", self.name_len)
+        self.bufsize = unpacker.offset - base
+class ListFontsWithInfoCookie(xcffib.Cookie):
+    reply_type = ListFontsWithInfoReply
+class type_padExtension(xcffib.Extension):
+    def ListFontsWithInfo(self, max_names, pattern_len, pattern, is_checked=True):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=xx2xHH", max_names, pattern_len))
+        buf.write(xcffib.pack_list(pattern, "c"))
+        return self.send_request(50, buf, ListFontsWithInfoCookie, is_checked=is_checked)
+xcffib._add_ext(key, type_padExtension, _events, _errors)
diff --git a/tests/generator/type_pad.xml b/tests/generator/type_pad.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/type_pad.xml
@@ -0,0 +1,111 @@
+<xcb header="type_pad">
+
+  <struct name="CHARINFO">
+    <field type="INT16" name="left_side_bearing" />
+    <field type="INT16" name="right_side_bearing" />
+    <field type="INT16" name="character_width" />
+    <field type="INT16" name="ascent" />
+    <field type="INT16" name="descent" />
+    <field type="CARD16" name="attributes" />
+  </struct>
+
+  <xidtype name="ATOM" />
+
+  <struct name="FONTPROP">
+    <field type="ATOM" name="name" />
+    <field type="CARD32" name="value" />
+  </struct>
+
+  <request name="ListFontsWithInfo" opcode="50">
+    <pad bytes="1" />
+    <field type="CARD16" name="max_names" />
+    <field type="CARD16" name="pattern_len" />
+    <list type="char" name="pattern">
+      <fieldref>pattern_len</fieldref>
+    </list>
+    <reply>
+      <field type="CARD8" name="name_len" />
+      <field type="CHARINFO" name="min_bounds" />
+      <pad bytes="4" />
+      <field type="CHARINFO" name="max_bounds" />
+      <pad bytes="4" />
+      <field type="CARD16" name="min_char_or_byte2" />
+      <field type="CARD16" name="max_char_or_byte2" />
+      <field type="CARD16" name="default_char" />
+      <field type="CARD16" name="properties_len" />
+      <field type="BYTE" name="draw_direction" enum="FontDraw" />
+      <field type="CARD8" name="min_byte1" />
+      <field type="CARD8" name="max_byte1" />
+      <field type="BOOL" name="all_chars_exist" />
+      <field type="INT16" name="font_ascent" />
+      <field type="INT16" name="font_descent" />
+      <field type="CARD32" name="replies_hint" />
+      <list type="FONTPROP" name="properties">
+        <fieldref>properties_len</fieldref>
+      </list>
+      <list type="char" name="name">
+        <fieldref>name_len</fieldref>
+      </list>
+      <doc>
+        <field name="name_len"><![CDATA[
+The number of matched font names.
+        ]]></field>
+        <field name="min_bounds"><![CDATA[
+minimum bounds over all existing char
+        ]]></field>
+        <field name="max_bounds"><![CDATA[
+maximum bounds over all existing char
+        ]]></field>
+        <field name="min_char_or_byte2"><![CDATA[
+first character
+        ]]></field>
+        <field name="max_char_or_byte2"><![CDATA[
+last character
+        ]]></field>
+        <field name="default_char"><![CDATA[
+char to print for undefined character
+        ]]></field>
+        <field name="properties_len"><![CDATA[
+how many properties there are
+        ]]></field>
+        <field name="all_chars_exist"><![CDATA[
+flag if all characters have nonzero size
+        ]]></field>
+        <field name="font_ascent"><![CDATA[
+baseline to top edge of raster
+        ]]></field>
+        <field name="font_descent"><![CDATA[
+baseline to bottom edge of raster
+        ]]></field>
+        <field name="replies_hint"><![CDATA[
+An indication of how many more fonts will be returned. This is only a hint and
+may be larger or smaller than the number of fonts actually returned. A zero
+value does not guarantee that no more fonts will be returned.
+        ]]></field>
+        <!-- enum doc is sufficient -->
+        <field name="draw_direction" />
+      </doc>
+    </reply>
+    <doc>
+      <brief>get matching font names and information</brief>
+      <description><![CDATA[
+Gets a list of available font names which match the given `pattern`.
+      ]]></description>
+      <field name="pattern_len"><![CDATA[
+The length (in bytes) of `pattern`.
+      ]]></field>
+      <field name="pattern"><![CDATA[
+A font pattern, for example "-misc-fixed-*".
+
+The asterisk (*) is a wildcard for any number of characters. The question mark
+(?) is a wildcard for a single character. Use of uppercase or lowercase does
+not matter.
+      ]]></field>
+      <field name="max_names"><![CDATA[
+The maximum number of fonts to be returned.
+      ]]></field>
+    </doc>
+
+  </request>
+
+</xcb>
diff --git a/tests/generator/union.py b/tests/generator/union.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/union.py
@@ -0,0 +1,16 @@
+import xcffib
+import struct
+import six
+_events = {}
+_errors = {}
+class ClientMessageData(xcffib.Union):
+    def __init__(self, unpacker):
+        xcffib.Union.__init__(self, unpacker)
+        self.data8 = xcffib.List(unpacker.copy(), "B", 20)
+        self.data16 = xcffib.List(unpacker.copy(), "H", 10)
+        self.data32 = xcffib.List(unpacker.copy(), "I", 5)
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(xcffib.pack_list(self.data8, "B"))
+        return buf.getvalue()
+xcffib._add_ext(key, unionExtension, _events, _errors)
diff --git a/tests/generator/union.xml b/tests/generator/union.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/union.xml
@@ -0,0 +1,12 @@
+<!-- based on xproto -->
+<xcb header="union">
+
+  <union name="ClientMessageData">
+    <!-- The format member of the ClientMessage event determines which array
+         to use. -->
+    <list type="CARD8"  name="data8" ><value>20</value></list> <!--  8 -->
+    <list type="CARD16" name="data16"><value>10</value></list> <!-- 16 -->
+    <list type="CARD32" name="data32"><value>5</value></list>  <!-- 32 -->
+  </union>
+
+</xcb>
diff --git a/tests/generator/xproto_1.7.py b/tests/generator/xproto_1.7.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/xproto_1.7.py
@@ -0,0 +1,80 @@
+import xcffib
+import struct
+import six
+MAJOR_VERSION = 0
+MINOR_VERSION = 11
+key = xcffib.ExtensionKey("XPROTO")
+_events = {}
+_errors = {}
+class Atom:
+    _None = 0
+    Any = 0
+    PRIMARY = 1
+    SECONDARY = 2
+    ARC = 3
+    ATOM = 4
+    BITMAP = 5
+    CARDINAL = 6
+    COLORMAP = 7
+    CURSOR = 8
+    CUT_BUFFER0 = 9
+    CUT_BUFFER1 = 10
+    CUT_BUFFER2 = 11
+    CUT_BUFFER3 = 12
+    CUT_BUFFER4 = 13
+    CUT_BUFFER5 = 14
+    CUT_BUFFER6 = 15
+    CUT_BUFFER7 = 16
+    DRAWABLE = 17
+    FONT = 18
+    INTEGER = 19
+    PIXMAP = 20
+    POINT = 21
+    RECTANGLE = 22
+    RESOURCE_MANAGER = 23
+    RGB_COLOR_MAP = 24
+    RGB_BEST_MAP = 25
+    RGB_BLUE_MAP = 26
+    RGB_DEFAULT_MAP = 27
+    RGB_GRAY_MAP = 28
+    RGB_GREEN_MAP = 29
+    RGB_RED_MAP = 30
+    STRING = 31
+    VISUALID = 32
+    WINDOW = 33
+    WM_COMMAND = 34
+    WM_HINTS = 35
+    WM_CLIENT_MACHINE = 36
+    WM_ICON_NAME = 37
+    WM_ICON_SIZE = 38
+    WM_NAME = 39
+    WM_NORMAL_HINTS = 40
+    WM_SIZE_HINTS = 41
+    WM_ZOOM_HINTS = 42
+    MIN_SPACE = 43
+    NORM_SPACE = 44
+    MAX_SPACE = 45
+    END_SPACE = 46
+    SUPERSCRIPT_X = 47
+    SUPERSCRIPT_Y = 48
+    SUBSCRIPT_X = 49
+    SUBSCRIPT_Y = 50
+    UNDERLINE_POSITION = 51
+    UNDERLINE_THICKNESS = 52
+    STRIKEOUT_ASCENT = 53
+    STRIKEOUT_DESCENT = 54
+    ITALIC_ANGLE = 55
+    X_HEIGHT = 56
+    QUAD_WIDTH = 57
+    WEIGHT = 58
+    POINT_SIZE = 59
+    RESOLUTION = 60
+    COPYRIGHT = 61
+    NOTICE = 62
+    FONT_NAME = 63
+    FAMILY_NAME = 64
+    FULL_NAME = 65
+    CAP_HEIGHT = 66
+    WM_CLASS = 67
+    WM_TRANSIENT_FOR = 68
+xcffib._add_ext(key, xproto_1._7Extension, _events, _errors)
diff --git a/tests/generator/xproto_1.7.xml b/tests/generator/xproto_1.7.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/xproto_1.7.xml
@@ -0,0 +1,81 @@
+<!-- rendering of this enum in xcb-proto 1.7 is vastly more complicated than in
+     more modern versions of xcb-proto, but for completness we should render
+     this correctly as well -->
+<?xml version="1.0" encoding="utf-8"?>
+<xcb header="xproto_1.7" extension-xname="XPROTO" extension-name="xproto"
+    major-version="0" minor-version="11">
+
+  <enum name="Atom">
+    <item name="None"> <value>0</value></item>
+    <item name="Any">  <value>0</value></item>
+    <item name="PRIMARY" />
+    <item name="SECONDARY" />
+    <item name="ARC" />
+    <item name="ATOM" />
+    <item name="BITMAP" />
+    <item name="CARDINAL" />
+    <item name="COLORMAP" />
+    <item name="CURSOR" />
+    <item name="CUT_BUFFER0" />
+    <item name="CUT_BUFFER1" />
+    <item name="CUT_BUFFER2" />
+    <item name="CUT_BUFFER3" />
+    <item name="CUT_BUFFER4" />
+    <item name="CUT_BUFFER5" />
+    <item name="CUT_BUFFER6" />
+    <item name="CUT_BUFFER7" />
+    <item name="DRAWABLE" />
+    <item name="FONT" />
+    <item name="INTEGER" />
+    <item name="PIXMAP" />
+    <item name="POINT" />
+    <item name="RECTANGLE" />
+    <item name="RESOURCE_MANAGER" />
+    <item name="RGB_COLOR_MAP" />
+    <item name="RGB_BEST_MAP" />
+    <item name="RGB_BLUE_MAP" />
+    <item name="RGB_DEFAULT_MAP" />
+    <item name="RGB_GRAY_MAP" />
+    <item name="RGB_GREEN_MAP" />
+    <item name="RGB_RED_MAP" />
+    <item name="STRING" />
+    <item name="VISUALID" />
+    <item name="WINDOW" />
+    <item name="WM_COMMAND" />
+    <item name="WM_HINTS" />
+    <item name="WM_CLIENT_MACHINE" />
+    <item name="WM_ICON_NAME" />
+    <item name="WM_ICON_SIZE" />
+    <item name="WM_NAME" />
+    <item name="WM_NORMAL_HINTS" />
+    <item name="WM_SIZE_HINTS" />
+    <item name="WM_ZOOM_HINTS" />
+    <item name="MIN_SPACE" />
+    <item name="NORM_SPACE" />
+    <item name="MAX_SPACE" />
+    <item name="END_SPACE" />
+    <item name="SUPERSCRIPT_X" />
+    <item name="SUPERSCRIPT_Y" />
+    <item name="SUBSCRIPT_X" />
+    <item name="SUBSCRIPT_Y" />
+    <item name="UNDERLINE_POSITION" />
+    <item name="UNDERLINE_THICKNESS" />
+    <item name="STRIKEOUT_ASCENT" />
+    <item name="STRIKEOUT_DESCENT" />
+    <item name="ITALIC_ANGLE" />
+    <item name="X_HEIGHT" />
+    <item name="QUAD_WIDTH" />
+    <item name="WEIGHT" />
+    <item name="POINT_SIZE" />
+    <item name="RESOLUTION" />
+    <item name="COPYRIGHT" />
+    <item name="NOTICE" />
+    <item name="FONT_NAME" />
+    <item name="FAMILY_NAME" />
+    <item name="FULL_NAME" />
+    <item name="CAP_HEIGHT" />
+    <item name="WM_CLASS" />
+    <item name="WM_TRANSIENT_FOR" />
+  </enum>
+
+</xcb>
diff --git a/xcffib.cabal b/xcffib.cabal
--- a/xcffib.cabal
+++ b/xcffib.cabal
@@ -1,5 +1,5 @@
 name:                xcffib
-version:             0.2.1
+version:             0.2.2
 synopsis:            A cffi-based python binding for X
 homepage:            http://github.com/tych0/xcffib
 license:             OtherLicense
@@ -11,6 +11,13 @@
 cabal-version:       >=1.8
 bug-reports:         https://github.com/tych0/xcffib/issues
 description: A cffi-based python binding for X, comparable to xpyb
+extra-source-files: tests/generator/*.py,
+                    tests/generator/*.xml,
+                    -- cabal's wildcarding is broken if the filename contains
+                    -- extra dots:
+                    -- https://github.com/haskell/cabal/issues/784
+                    tests/generator/*.7.py,
+                    tests/generator/*.7.xml
 
 source-repository head
   type:              git
