// vim: ts=2 sw=2 et /* * These tests are of limited usefulness. In fact, you might even say that * they're not really tests at all. But I felt that it would be useful to have * some basic usage of most functions just to verify that things compile and * work generally */ #include #include #include #include #include using namespace boost::unit_test; #include #include #include #include using namespace Cairo; // little utility helper classes struct TestSetup { TestSetup() { surface = ImageSurface::create(Cairo::FORMAT_ARGB32, 100, 100); cr = Cairo::Context::create(surface); } RefPtr cr; RefPtr surface; }; // a no-op-render user font base class class NullRenderUserFont : public UserFontFace { public: ErrorStatus render_glyph(const RefPtr& /*scaled_font*/, unsigned long /*glyph*/, const RefPtr& /*cr*/, TextExtents& /*metrics*/) { ++count_render_glyph; return CAIRO_STATUS_SUCCESS; } int count_render_glyph; protected: NullRenderUserFont() : UserFontFace(), count_render_glyph(0) {} }; /****************************** * test_implement_text ******************************/ class ImplTextUserFont: public NullRenderUserFont { public: static RefPtr create() { return make_refptr_for_insance(new ImplTextUserFont());}; ErrorStatus text_to_glyphs(const RefPtr& /*scaled_font*/, const std::string& /*utf8*/, std::vector& glyphs, std::vector& /*clusters*/, TextClusterFlags& /*cluster_flags*/) override { ++count_text_to_glyphs; // return an arbitrary glyph Glyph g = {84, 0, 0}; glyphs.push_back(g); return CAIRO_STATUS_SUCCESS; } int count_text_to_glyphs; protected: ImplTextUserFont() : count_text_to_glyphs(0) {} }; void test_implement_text() { TestSetup setup; auto font = ImplTextUserFont::create(); setup.cr->set_font_face(font); setup.cr->show_text("hello"); BOOST_REQUIRE(font->count_text_to_glyphs > 0); BOOST_REQUIRE(font->count_render_glyph > 0); } /****************************** * test_implement_unicode ******************************/ class ImplUnicodeUserFont: public NullRenderUserFont { public: static RefPtr create() { return make_refptr_for_instance(new ImplUnicodeUserFont());}; ErrorStatus unicode_to_glyph(const RefPtr& /*scaled_font*/, unsigned long /*unicode*/, unsigned long& /*glyph*/) override { ++count_unicode_to_glyph; return CAIRO_STATUS_SUCCESS;} int count_unicode_to_glyph; protected: ImplUnicodeUserFont() : NullRenderUserFont(), count_unicode_to_glyph(0) {} }; void test_implement_unicode() { TestSetup setup; auto font = ImplTextUserFont::create(); setup.cr->set_font_face(font); setup.cr->show_text("hello"); BOOST_REQUIRE(font->count_text_to_glyphs > 0); BOOST_REQUIRE(font->count_render_glyph > 0); } /****************************** * test_implement_both ******************************/ class ImplBothUserFont: public NullRenderUserFont { public: static RefPtr create() { return make_refptr_for_instance(new ImplBothUserFont());}; ErrorStatus unicode_to_glyph(const RefPtr& /*scaled_font*/, unsigned long /*unicode*/, unsigned long& /*glyph*/) override { ++count_unicode_to_glyph; return CAIRO_STATUS_SUCCESS;} int count_unicode_to_glyph; ErrorStatus text_to_glyphs(const RefPtr& /*scaled_font*/, const std::string& /*utf8*/, std::vector& glyphs, std::vector& /*clusters*/, TextClusterFlags& /*cluster_flags*/) override { ++count_text_to_glyphs; // return an arbitrary glyph Glyph g = {84, 0, 0}; glyphs.push_back(g); return CAIRO_STATUS_SUCCESS; } int count_text_to_glyphs; protected: ImplBothUserFont() : NullRenderUserFont(), count_unicode_to_glyph(0), count_text_to_glyphs(0) {} }; void test_implement_both() { TestSetup setup; auto font = ImplBothUserFont::create(); setup.cr->set_font_face(font); setup.cr->show_text("hello"); // text_to_glyphs should take precedence BOOST_REQUIRE(font->count_text_to_glyphs > 0); BOOST_REQUIRE(font->count_unicode_to_glyph == 0); BOOST_REQUIRE(font->count_render_glyph > 0); } /****************************** * test_implement_neither ******************************/ class ImplNeitherUserFont: public NullRenderUserFont { public: static RefPtr create() { return make_refptr_for_instance(new ImplNeitherUserFont());}; protected: ImplNeitherUserFont() : NullRenderUserFont() {} }; void test_implement_neither() { TestSetup setup; auto font = ImplNeitherUserFont::create(); setup.cr->set_font_face(font); setup.cr->show_text("hello"); BOOST_REQUIRE(font->count_render_glyph > 0); } /****************************** * test_implement_init ******************************/ class ImplInitUserFont: public NullRenderUserFont { public: static RefPtr create() { return make_refptr_for_instance(new ImplInitUserFont());}; ErrorStatus init(const RefPtr& /*scaled_font*/, const RefPtr& /*cr*/, FontExtents& /*extents*/) override {++count_init; return CAIRO_STATUS_SUCCESS;} int count_init; protected: ImplInitUserFont() : NullRenderUserFont(), count_init(0) {} }; void test_implement_init() { TestSetup setup; auto font = ImplInitUserFont::create(); setup.cr->set_font_face(font); setup.cr->show_text("hello"); BOOST_REQUIRE(font->count_init > 0); BOOST_REQUIRE(font->count_render_glyph > 0); } class ExceptionUserFont : public UserFontFace { public: static RefPtr create(int flags) { return make_refptr_for_instance(new ExceptionUserFont(flags));}; ErrorStatus render_glyph(const RefPtr& /*scaled_font*/, unsigned long /*glyph*/, const RefPtr& /*cr*/, TextExtents& /*metrics*/) { count_render_glyph++; if (m_flags & FLAG_RENDER) throw std::logic_error("render-glyph exception"); return CAIRO_STATUS_SUCCESS; } ErrorStatus unicode_to_glyph(const RefPtr& /*scaled_font*/, unsigned long unicode, unsigned long& glyph) { count_unicode_to_glyph++; if (m_flags & FLAG_UNICODE) throw std::logic_error("unicode-to-glyph exception"); glyph = unicode; return CAIRO_STATUS_SUCCESS; } ErrorStatus init(const RefPtr& /*scaled_font*/, const RefPtr& /*cr*/, FontExtents& /*extents*/) override { count_init++; if (m_flags & FLAG_INIT) throw std::logic_error("init exception"); return CAIRO_STATUS_SUCCESS; } int count_render_glyph; int count_text_to_glyphs; int count_unicode_to_glyph; int count_init; int m_flags; static const int FLAG_INIT = 1 << 0; static const int FLAG_UNICODE = 1 << 1; static const int FLAG_RENDER = 1 << 2; protected: ExceptionUserFont(int flags) : UserFontFace(), count_render_glyph(0), count_text_to_glyphs(0), count_unicode_to_glyph(0), count_init(0), m_flags(flags) {} }; void test_user_font_exception() { auto font = ExceptionUserFont::create(ExceptionUserFont::FLAG_INIT); BOOST_CHECK(font); // the init() callback will throw an exception, if this isn't handled in the // callback wrapper, the program will abort since an exception can't unwind // through C code. However, due to the exception being thrown, the create() // function will fail and throw a new exception. So if the executable doesn't // abort, we should get an exception here. Cairo::RefPtr scaled_font; BOOST_CHECK_THROW (scaled_font = Cairo::ScaledFont::create(font, Cairo::scaling_matrix(10, 10), Cairo::identity_matrix(), Cairo::FontOptions()), Cairo::logic_error); BOOST_CHECK (font->count_init > 0); // now test when an exception is thrown in unicode_to_glyph font = ExceptionUserFont::create(ExceptionUserFont::FLAG_UNICODE); BOOST_CHECK_NO_THROW (scaled_font = Cairo::ScaledFont::create(font, Cairo::scaling_matrix(10, 10), Cairo::identity_matrix(), Cairo::FontOptions())); TestSetup setup; setup.cr->set_font_face(font); // this call should throw an exception since the callback wrapper will return // an error status (that will be translated into an exception) but the test // shouldn't abort since the callback exceptions are handled by the callback // wrapper BOOST_REQUIRE_EQUAL (CAIRO_STATUS_SUCCESS, font->get_status()); BOOST_CHECK_THROW(setup.cr->show_text("Hello, world"), Cairo::logic_error); BOOST_CHECK(font->count_unicode_to_glyph > 0); BOOST_CHECK_EQUAL(font->count_render_glyph, 0); // now test when an exception is thrown in render_glyph font = ExceptionUserFont::create(ExceptionUserFont::FLAG_RENDER); BOOST_CHECK_NO_THROW (scaled_font = Cairo::ScaledFont::create(font, Cairo::scaling_matrix(10, 10), Cairo::identity_matrix(), Cairo::FontOptions())); // need a new setup since the old cr is now in an error state, so attemtping // to use it will throw an exception TestSetup setup2; BOOST_CHECK_NO_THROW(setup2.cr->set_font_face(font)); BOOST_REQUIRE_EQUAL (CAIRO_STATUS_SUCCESS, font->get_status()); BOOST_CHECK_THROW(setup2.cr->show_text("Hello, world"), Cairo::logic_error); BOOST_CHECK (font->count_unicode_to_glyph > 0); BOOST_CHECK (font->count_render_glyph > 0); } test_suite* init_unit_test_suite(int argc, char* argv[]) { // compile even with -Werror if (argc && argv) {} test_suite* test= BOOST_TEST_SUITE( "Cairo::UserFontFace Tests" ); test->add (BOOST_TEST_CASE (&test_implement_text)); test->add (BOOST_TEST_CASE (&test_implement_unicode)); test->add (BOOST_TEST_CASE (&test_implement_both)); test->add (BOOST_TEST_CASE (&test_implement_neither)); test->add (BOOST_TEST_CASE (&test_implement_init)); test->add (BOOST_TEST_CASE (&test_user_font_exception)); return test; }