summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Burrows <Daniel Burrows Daniel_Burrows@alumni.brown.edu>2010-05-24 09:36:33 -0700
committerDaniel Burrows <Daniel Burrows Daniel_Burrows@alumni.brown.edu>2010-05-24 09:36:33 -0700
commit8b81c0c1e773819f1d531b4d44388193bb93fd9e (patch)
tree605bc7357c5cbb7aa870ec47d8de1fcd359926f2
parent88e3dc1c2841098538d30c13fb2ce5d164ced183 (diff)
downloadaptitude-8b81c0c1e773819f1d531b4d44388193bb93fd9e.tar.gz
Start using google-mock to test the search input controller logic.
I use google-mock to create a mock implementation of the view, then test that the logic interacts with it as expected. Right now, it doesn't. The ability to do this was part of why I wanted to separate the logic from the view. I haven't added google-mock to configure.ac yet; need to do that later.
-rw-r--r--site_scons/aptitude_configure.py3
-rw-r--r--site_scons/aptitude_configure_checks.py27
-rw-r--r--src/gtk/views/mocks/search_input.h70
-rw-r--r--tests/Makefile.am7
-rw-r--r--tests/SConscript28
-rw-r--r--tests/boost_test_main.cc11
-rw-r--r--tests/test_search_input_controller.cc131
7 files changed, 276 insertions, 1 deletions
diff --git a/site_scons/aptitude_configure.py b/site_scons/aptitude_configure.py
index f46a31b5..46b4c184 100644
--- a/site_scons/aptitude_configure.py
+++ b/site_scons/aptitude_configure.py
@@ -132,6 +132,9 @@ the Boost unit tests need.'''
TryLibrary('boost_unit_test_framework') ]),
"Can't find Boost.Test")
+ RequireCheck(conf.CheckForGoogleMock(),
+ "Can't find google-mock")
+
conf.Finish()
def DoConfigureCppunitTests(env):
diff --git a/site_scons/aptitude_configure_checks.py b/site_scons/aptitude_configure_checks.py
index 75eee9cc..fd6006f9 100644
--- a/site_scons/aptitude_configure_checks.py
+++ b/site_scons/aptitude_configure_checks.py
@@ -236,6 +236,33 @@ int main(int argc, char **argv)
boost::iostreams::filtering_ostream compressed_devnull(boost::iostreams::zlib_compressor(9) | devnull);
}''', context.env['CXXFILESUFFIX'])
+@ConfigureCheck("Checking for google-mock")
+def CheckForGoogleMock(context):
+ """Look for gmock (headers and library).
+
+Brings gtest along for the ride, because otherwise gmock won't link."""
+
+ context.env.Append(LIBS = [ 'gmock', 'gtest' ])
+
+ return context.TryLink('''
+#include <gmock/gmock.h>
+
+class FooMock
+{
+public:
+ MOCK_METHOD1(foo, void(int));
+};
+
+int main(int argc, char **argv)
+{
+ ::testing::GTEST_FLAG(throw_on_failure) = true;
+ ::testing::InitGoogleMock(&argc, argv);
+
+ FooMock mock;
+ mock.foo(4);
+}''', context.env['CXXFILESUFFIX'])
+
+
@ConfigureCheck("Checking for Boost.Test")
def CheckForBoostTest(context):
"""Look for Boost.Test."""
diff --git a/src/gtk/views/mocks/search_input.h b/src/gtk/views/mocks/search_input.h
new file mode 100644
index 00000000..f70a0b5e
--- /dev/null
+++ b/src/gtk/views/mocks/search_input.h
@@ -0,0 +1,70 @@
+/** \file search_input.h */ // -*-c++-*-
+
+// Copyright (C) 2010 Daniel Burrows
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+#ifndef APTITUDE_GTK_VIEWS_MOCKS_SEARCH_INPUT_H
+#define APTITUDE_GTK_VIEWS_MOCKS_SEARCH_INPUT_H
+
+#include <gmock/gmock.h>
+#include <gtk/views/search_input.h>
+
+namespace gui
+{
+ namespace views
+ {
+ namespace mocks
+ {
+ /** \brief Mock implementation of search_input for use in unit
+ * tests.
+ *
+ * Provides signals which, by default, are connected by the
+ * connect_() methods.
+ */
+ class search_input : public views::search_input
+ {
+ public:
+ MOCK_METHOD0(get_search_text, Glib::ustring());
+ MOCK_METHOD1(set_search_text, void(const Glib::ustring &));
+ MOCK_METHOD1(set_error_message, void(const Glib::ustring &));
+ MOCK_METHOD1(set_input_validity, void(bool));
+ MOCK_METHOD1(set_find_sensitivity, void(bool));
+ MOCK_METHOD1(connect_search_text_changed, sigc::connection(const sigc::slot<void> &));
+ MOCK_METHOD1(connect_search, sigc::connection(const sigc::slot<void> &));
+
+ sigc::signal<void> signal_search_text_changed;
+ sigc::signal<void> signal;
+
+ search_input()
+ {
+ using testing::_;
+ using testing::Invoke;
+
+ ON_CALL(*this, connect_search_text_changed(_))
+ .WillByDefault(Invoke(&signal_search_text_changed,
+ &sigc::signal<void>::connect));
+
+ ON_CALL(*this, connect_search(_))
+ .WillByDefault(Invoke(&signal,
+ &sigc::signal<void>::connect));
+ }
+ };
+ }
+ }
+}
+
+#endif // APTITUDE_GTK_VIEWS_MOCKS_SEARCH_INPUT_H
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9a630f0d..755c632d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -2,13 +2,17 @@ MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/src -I$(srcdir)
BOOST_TEST_LDFLAGS = @BOOST_UNIT_TEST_LIBS@
+GMOCK_LDFLAGS = -lgmock -lgtest
AM_CPPFLAGS = -DBOOST_TEST_DYN_LINK -DSRCDIR=\"$(srcdir)\"
LDADD = $(top_builddir)/src/loggers.o \
+$(top_builddir)/src/gtk/controllers/libgtk-controllers.a \
+$(top_builddir)/src/gtk/views/libgtk-views.a \
$(top_builddir)/src/generic/apt/matching/libgeneric-matching.a \
$(top_builddir)/src/generic/apt/libgeneric-apt.a \
$(top_builddir)/src/generic/apt/matching/libgeneric-matching.a \
$(top_builddir)/src/generic/problemresolver/libgeneric-problemresolver.a \
-$(top_builddir)/src/generic/util/libgeneric-util.a -lcppunit $(BOOST_TEST_LDFLAGS)
+$(top_builddir)/src/generic/util/libgeneric-util.a -lcppunit \
+$(BOOST_TEST_LDFLAGS) $(GMOCK_LDFLAGS)
check_PROGRAMS = cppunit_test boost_test
@@ -51,4 +55,5 @@ boost_test_SOURCES = \
test_dynamic_set.cc \
test_enumerator.cc \
test_file_cache.cc \
+ test_search_input_controller.cc \
test_sqlite.cc
diff --git a/tests/SConscript b/tests/SConscript
index 658d47c0..b41e3358 100644
--- a/tests/SConscript
+++ b/tests/SConscript
@@ -67,15 +67,43 @@ boost_test_sources = [
'test_dynamic_set.cc',
'test_enumerator.cc',
'test_file_cache.cc',
+ 'test_search_input_controller.cc',
'test_sqlite.cc'
]
boost_test_extra_deps = [
'../src/loggers.o',
+ '../src/generic/apt/apt.o',
+ '../src/generic/apt/aptcache.o',
+ '../src/generic/apt/aptitude_resolver.o',
+ '../src/generic/apt/aptitude_resolver_cost_settings.o',
+ '../src/generic/apt/aptitude_resolver_cost_syntax.o',
+ '../src/generic/apt/aptitude_resolver_cost_types.o',
+ '../src/generic/apt/aptitude_resolver_universe.o',
+ '../src/generic/apt/aptitudepolicy.o',
+ '../src/generic/apt/config_signal.o',
+ '../src/generic/apt/download_queue.o',
+ '../src/generic/apt/dump_packages.o',
+ '../src/generic/apt/matching/compare_patterns.o',
+ '../src/generic/apt/matching/match.o',
+ '../src/generic/apt/matching/parse.o',
+ '../src/generic/apt/matching/pattern.o',
+ '../src/generic/apt/matching/serialize.o',
+ '../src/generic/apt/pkg_hier.o',
+ '../src/generic/apt/resolver_manager.o',
+ '../src/generic/apt/tags.o',
+ '../src/generic/apt/tasks.o',
+ '../src/generic/problemresolver/cost.o',
+ '../src/generic/problemresolver/cost_limits.o',
+ '../src/generic/problemresolver/incremental_expression.o',
'../src/generic/util/file_cache.o',
+ '../src/generic/util/refcounted_base.o',
'../src/generic/util/sqlite.o',
'../src/generic/util/temp.o',
+ '../src/generic/util/undo.o',
'../src/generic/util/util.o',
+ '../src/gtk/controllers/search_input.o',
+ '../src/gtk/views/search_input.o',
]
test_data_files = [
diff --git a/tests/boost_test_main.cc b/tests/boost_test_main.cc
index 40bf9eea..a4732d51 100644
--- a/tests/boost_test_main.cc
+++ b/tests/boost_test_main.cc
@@ -4,6 +4,8 @@
#include <boost/test/unit_test.hpp>
+#include <gmock/gmock.h>
+
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/level.h>
#include <log4cxx/logger.h>
@@ -27,6 +29,15 @@ int main(int argc, char **argv)
{
argv0 = argv[0];
+ // TODO: setting throw_on_failure is a hack; instead, we should
+ // configure the mock framework to emit Boost.Test errors.
+ // Unfortunately, I can't access the documentation (for the Google
+ // Test event listener API) that would tell me how to do this
+ // without a network connection. I hate libraries without offline
+ // documentation.
+ ::testing::GTEST_FLAG(throw_on_failure) = true;
+ ::testing::InitGoogleMock(&argc, argv);
+
bool debug = false;
for(int i = 1; i < argc; ++i)
{
diff --git a/tests/test_search_input_controller.cc b/tests/test_search_input_controller.cc
new file mode 100644
index 00000000..0eb54ba0
--- /dev/null
+++ b/tests/test_search_input_controller.cc
@@ -0,0 +1,131 @@
+/** \file test_search_input.cc */
+
+// Copyright (C) 2010 Daniel Burrows
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+#include <generic/apt/matching/compare_patterns.h>
+#include <generic/apt/matching/pattern.h>
+#include <gtk/controllers/search_input.h>
+#include <gtk/views/mocks/search_input.h>
+
+#include <boost/make_shared.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace ctrls = gui::controllers;
+namespace views = gui::views;
+namespace mocks = gui::views::mocks;
+
+using aptitude::matching::compare_patterns;
+using aptitude::matching::pattern;
+using boost::make_shared;
+using boost::shared_ptr;
+using cwidget::util::ref_ptr;
+using testing::InSequence;
+using testing::NiceMock;
+using testing::StrictMock;
+
+namespace
+{
+ MATCHER_P(PatternsEqual,
+ expected,
+ "")
+ {
+ return compare_patterns(arg, expected) == 0;
+ }
+
+ // Mock class that lets us capture the controller's outgoing
+ // signals.
+ class controller_callbacks
+ {
+ public:
+ MOCK_METHOD2(activated, void(Glib::ustring, cwidget::util::ref_ptr<aptitude::matching::pattern>));
+ };
+
+ struct SearchInputTest
+ {
+ boost::shared_ptr<mocks::search_input> view;
+ boost::shared_ptr<mocks::search_input> viewNice;
+ boost::shared_ptr<mocks::search_input> viewStrict;
+
+ controller_callbacks callbacks;
+ controller_callbacks callbacksNice;
+ controller_callbacks callbacksStrict;
+
+ // Controllers are initialized lazily, to give us a chance to
+ // register expectations with the views first.
+ private:
+ boost::shared_ptr<ctrls::search_input> controller;
+ boost::shared_ptr<ctrls::search_input> controllerNice;
+ boost::shared_ptr<ctrls::search_input> controllerStrict;
+
+ public:
+ boost::shared_ptr<ctrls::search_input> get_controller()
+ {
+ if(controller.get() == NULL)
+ {
+ controller = ctrls::create_search_input(view);
+ controller->connect_activated(sigc::mem_fun(callbacks,
+ &controller_callbacks::activated));
+ }
+ return controller;
+ }
+
+ boost::shared_ptr<ctrls::search_input> get_controllerNice()
+ {
+ if(controllerNice.get() == NULL)
+ {
+ controllerNice = ctrls::create_search_input(view);
+ controllerNice->connect_activated(sigc::mem_fun(callbacksNice,
+ &controller_callbacks::activated));
+ }
+ return controllerNice;
+ }
+
+ boost::shared_ptr<ctrls::search_input> get_controllerStrict()
+ {
+ if(controllerStrict.get() == NULL)
+ {
+ controllerStrict = ctrls::create_search_input(view);
+ controllerStrict->connect_activated(sigc::mem_fun(callbacksStrict,
+ &controller_callbacks::activated));
+ }
+ return controllerStrict;
+ }
+
+ SearchInputTest()
+ : view(make_shared<mocks::search_input>()),
+ viewNice(make_shared<NiceMock<mocks::search_input> >()),
+ viewStrict(make_shared<StrictMock<mocks::search_input> >())
+ {
+ }
+ };
+}
+
+BOOST_FIXTURE_TEST_CASE(testEnteringCorrectTextSearches, SearchInputTest)
+{
+ ref_ptr<pattern> p = pattern::make_installed();
+ Glib::ustring p_text = "?installed";
+
+ {
+ InSequence dummy;
+
+ EXPECT_CALL(*view, set_search_text(p_text));
+ EXPECT_CALL(callbacks, activated(p_text, PatternsEqual(p)));
+ }
+
+ get_controller()->enter_text(p_text);
+}