int main(int argc, char * argv[])
{
    gr_face * face = 0;
    try
	{
		if (argc != 2)	throw std::length_error("not enough arguments: need a backing font");

		dummyFace = face_handle(argv[1]);
		testFeatTable<FeatTableTestA>(testDataA, "A\n");
		testFeatTable<FeatTableTestB>(testDataB, "B\n");
		testFeatTable<FeatTableTestB>(testDataBunsorted, "Bu\n");
		testFeatTable<FeatTableTestC>(testDataCunsorted, "C\n");
		testFeatTable<FeatTableTestD>(testDataDunsorted, "D\n");
		testFeatTable<FeatTableTestE>(testDataE, "E\n");

		// test a bad settings offset stradling the end of the table
		FeatureMap testFeatureMap;
		dummyFace.replace_table(TtfUtil::Tag::Feat, &testBadOffset, sizeof testBadOffset);
		face = gr_make_face_with_ops(&dummyFace, &face_handle::ops, gr_face_dumbRendering);
		bool readStatus = testFeatureMap.readFeats(*face);
		testAssert("fail gracefully on bad table", !readStatus);
	}
	catch (std::exception & e)
	{
		fprintf(stderr, "%s: %s\n", argv[0], e.what());
		gr_face_destroy(face);
		return 1;
	}

    gr_face_destroy(face);
    return 0;
}
template <class T> void testFeatTable(const T & table, const char * testName)
{
    FeatureMap testFeatureMap;
    dummyFace.replace_table(TtfUtil::Tag::Feat, &table, sizeof(T));
    gr_face * face = gr_make_face_with_ops(&dummyFace, &face_handle::ops, gr_face_dumbRendering);
    if (!face) throw std::runtime_error("failed to load font");
    bool readStatus = testFeatureMap.readFeats(*face);
    testAssert("readFeats", readStatus);
    fprintf(stderr, testName, NULL);
    testAssertEqual("test num features %hu,%hu\n", testFeatureMap.numFeats(), table.m_header.m_numFeat);

    for (size_t i = 0; i < sizeof(table.m_defs) / sizeof(FeatDefn); i++)
    {
        const FeatureRef * ref = testFeatureMap.findFeatureRef(table.m_defs[i].m_featId);
        testAssert("test feat\n", ref);
        testAssertEqual("test feat settings %hu %hu\n", ref->getNumSettings(), table.m_defs[i].m_numFeatSettings);
        testAssertEqual("test feat label %hu %hu\n", ref->getNameId(), table.m_defs[i].m_label);
        size_t settingsIndex = (table.m_defs[i].m_settingsOffset - sizeof(FeatHeader)
            - (sizeof(FeatDefn) * table.m_header.m_numFeat)) / sizeof(FeatSetting);
        for (size_t j = 0; j < table.m_defs[i].m_numFeatSettings; j++)
        {
            testAssertEqual("setting label %hu %hu\n", ref->getSettingName(j),
                       table.m_settings[settingsIndex+j].m_label);
        }
    }
    gr_face_destroy(face);
}