=== modified file 'softwarecenter/db/application.py'
--- softwarecenter/db/application.py	2012-09-04 09:13:13 +0000
+++ softwarecenter/db/application.py	2012-09-05 10:32:18 +0000
@@ -579,11 +579,18 @@
         """ The raw price, useful for e.g. sort-by """
         if self._doc:
             return self._doc.get_value(XapianValues.PRICE)
+        # the unity-lens expects a "" string here for "no-price"
+        return ""
 
     @property
     def price(self):
-        """ The price and the currency ready to display to the user """
+        """ The price and the currency ready to display to the user
+            or "Free" is its a libre or gratis app
+        """
         raw_price = self.raw_price
+        if raw_price == '0.00':
+            # TRANSLATORS: Free here means Gratis
+            return _("Free")
         currency = self.currency
         if raw_price and currency:
             # FIXME:  need to determine the currency dynamically once we can
@@ -597,7 +604,8 @@
             #        to format them here differently too, e.g.
             #        "US$ 1" but "1EUR"
             return "%s %s" % (currency, raw_price)
-        return ""
+        # TRANSLATORS: Free here means Libre
+        return _("Free")
 
     @property
     def supported_distros(self):

=== modified file 'softwarecenter/ui/gtk3/widgets/buttons.py'
--- softwarecenter/ui/gtk3/widgets/buttons.py	2012-05-30 18:39:55 +0000
+++ softwarecenter/ui/gtk3/widgets/buttons.py	2012-09-05 10:32:18 +0000
@@ -22,7 +22,6 @@
 from gettext import gettext as _
 
 from softwarecenter.backend import get_install_backend
-from softwarecenter.db.application import AppDetails
 from softwarecenter.enums import Icons
 from softwarecenter.ui.gtk3.em import StockEms, em
 from softwarecenter.ui.gtk3.drawing import darken
@@ -38,6 +37,8 @@
         image = image.set_from_pixbuf(icon.get_pixbuf())
     elif isinstance(icon, str):
         image = image.set_from_icon_name(icon, icon_size)
+    elif icon is None:
+        image = Gtk.Image()
     else:
         msg = "Acceptable icon values: None, GdkPixbuf, GtkImage or str"
         raise TypeError(msg)
@@ -246,15 +247,8 @@
             _global_featured_tile_width = max(_global_featured_tile_width,
                                               req_width)
 
-        details = AppDetails(db=helper.db, doc=doc)
-        # TRANSLATORS: Free here means Gratis
-        price = details.price or _("Free")
-        if price == '0.00':
-            # TRANSLATORS: Free here means Gratis
-            price = _("Free")
-        # TRANSLATORS: Free here means Gratis
-        if price != _("Free"):
-            price = 'US$ ' + price
+        # TRANSLATORS: Free here means Gratis
+        price = helper.get_display_price(doc)
         self.price = Gtk.Label.new(
             '<span font_desc="%i">%s</span>' % (em(0.6), price))
         self.price.set_use_markup(True)

=== added file 'tests/gtk3/test_buttons.py'
--- tests/gtk3/test_buttons.py	1970-01-01 00:00:00 +0000
+++ tests/gtk3/test_buttons.py	2012-09-05 10:32:18 +0000
@@ -0,0 +1,33 @@
+import unittest
+
+from tests.utils import (
+    get_mock_app_properties_helper,
+    setup_test_env,
+)
+setup_test_env()
+
+from softwarecenter.ui.gtk3.widgets.buttons import FeaturedTile
+
+
+class TestWidgets(unittest.TestCase):
+    """ basic tests for the TileButton widget """
+
+    def test_feature_tile_dup_symbol(self):
+        values = {'display_price': 'US$ 1.00' }
+        mock_property_helper = get_mock_app_properties_helper(values)
+        # we don't really need a "doc" on second input as we mock the helper
+        button = FeaturedTile(mock_property_helper, None)
+        self.assertEqual(
+            button.price.get_label(), '<span font_desc="10">US$ 1.00</span>')
+
+    def test_free_price(self):
+        values = {'display_price': "Free"}
+        mock_property_helper = get_mock_app_properties_helper(values)
+        # we don't really need a "doc" on second input as we mock the helper
+        button = FeaturedTile(mock_property_helper, None)
+        self.assertEqual(
+            button.price.get_label(), '<span font_desc="10">Free</span>')
+
+
+if __name__ == "__main__":
+    unittest.main()

=== modified file 'tests/test_database.py'
--- tests/test_database.py	2012-08-28 13:07:22 +0000
+++ tests/test_database.py	2012-09-05 10:32:18 +0000
@@ -266,7 +266,8 @@
                 "http://screenshots.ubuntu.com/thumbnail-with-version/software-center/[\d.]+",
                 appdetails.thumbnail))
         # FIXME: add document that has a price
-        self.assertEqual(appdetails.price, None)
+        self.assertEqual(appdetails.price, "Free")
+        self.assertEqual(appdetails.raw_price, "")
         self.assertEqual(appdetails.license, "Open source")
         # test lazy history loading for installation date
         self.ensure_installation_date_and_lazy_history_loading(appdetails)

=== modified file 'tests/test_dataprovider.py'
--- tests/test_dataprovider.py	2012-09-04 09:13:13 +0000
+++ tests/test_dataprovider.py	2012-09-05 10:32:18 +0000
@@ -34,7 +34,8 @@
         self.assertEqual(result["icon"], "accessories-text-editor")
         self.assertEqual(result["name"], "gedit")
         self.assertEqual(result["pkgname"], "gedit")
-        self.assertEqual(result["price"], "")
+        self.assertEqual(result["price"], "Free")
+        self.assertEqual(result["raw_price"], "")
 
 
 if __name__ == "__main__":

=== modified file 'tests/test_testutils.py'
--- tests/test_testutils.py	2012-05-30 18:39:55 +0000
+++ tests/test_testutils.py	2012-09-05 10:32:18 +0000
@@ -1,13 +1,13 @@
 import unittest
 
 import dbus
-import time
-from gi.repository import GObject
 
 from tests.utils import (
+    do_events_with_sleep,
     setup_test_env,
     start_dummy_backend,
     stop_dummy_backend,
+    get_mock_app_properties_helper,
 )
 setup_test_env()
 
@@ -15,7 +15,7 @@
 from softwarecenter.backend.installbackend_impl.aptd import get_dbus_bus
 
 
-class TestTestUtils(unittest.TestCase):
+class DummyBackendTestUtilsTestCase(unittest.TestCase):
 
     def setUp(self):
         start_dummy_backend()
@@ -32,7 +32,7 @@
         # get names and ...
         names = bus.list_names()
         # ensure we have the  following:
-        #  org.freedesktop.DBus, 
+        #  org.freedesktop.DBus,
         #  org.freedesktop.PolicyKit1
         #  org.debian.apt
         # (and :1.0, :1.1, :1.2)
@@ -42,14 +42,22 @@
         from softwarecenter.backend import get_install_backend
         backend = get_install_backend()
         backend.install(Application("2vcard", ""), iconname="")
-        self._p()
-
-    def _p(self):
-        context = GObject.main_context_default()
-        for i in range(10):
-            while context.pending():
-                context.iteration()
-            time.sleep(0.1)
+        do_events_with_sleep()
+
+
+class TestUtilsTestCase(unittest.TestCase):
+
+    def test_app_properties_helper_mock_with_defaults(self):
+        app_properties_helper = get_mock_app_properties_helper()
+        self.assertEqual(
+            app_properties_helper.get_pkgname(None), "apkg")
+
+    def test_app_properties_helper_mock_with_custom_values(self):
+        my_defaults = {'pkgname': 'diemoldau',
+                      }
+        app_properties_helper = get_mock_app_properties_helper(my_defaults)
+        self.assertEqual(
+            app_properties_helper.get_pkgname(None), "diemoldau")
 
 
 if __name__ == "__main__":

=== modified file 'tests/utils.py'
--- tests/utils.py	2012-08-23 14:37:28 +0000
+++ tests/utils.py	2012-09-05 10:32:18 +0000
@@ -43,6 +43,7 @@
     get_viewmanager,
 )
 from softwarecenter.ui.gtk3.utils import get_sc_icon_theme
+from softwarecenter.ui.gtk3.models.appstore2 import AppPropertiesHelper
 from softwarecenter.utils import get_uuid
 from softwarecenter.db.update import update_from_app_install_data
 
@@ -196,6 +197,49 @@
     return mock_options
 
 
+def get_mock_app_properties_helper(override_values={}):
+    """Return a mock suitable as a AppPropertiesHelper.
+
+    It can be passed a "values" dict for customization. But it will
+    return always the same data for each "doc" document (it will
+    not even look at doc)
+    """
+    # provide some defaults
+    values = { 
+        'appname': 'some Appname',
+        'pkgname': 'apkg',
+        'categories': 'cat1,cat2,lolcat',
+        'ratings_average': 3.5,
+        'ratings_total': 12,
+        'icon': None,
+        'display_price': '',
+        }
+    # override
+    values.update(override_values)
+    # do it
+    mock_property_helper = Mock(AppPropertiesHelper)
+    mock_property_helper.get_appname.return_value = values["appname"]
+    mock_property_helper.get_pkgname.return_value = values["pkgname"]
+    mock_property_helper.get_categories.return_value = values["categories"]
+    mock_property_helper.get_display_price.return_value = values[
+        "display_price"]
+    
+    mock_property_helper.db = Mock()
+    mock_property_helper.db._aptcache = FakedCache()
+    mock_property_helper.db.get_pkgname.return_value = values["pkgname"]
+    mock_property_helper.db.get_appname.return_value = values["appname"]
+
+    mock_ratings = Mock()
+    mock_ratings.ratings_average = values["ratings_average"]
+    mock_ratings.ratings_total = values["ratings_total"]
+
+    mock_property_helper.get_review_stats.return_value = mock_ratings
+    mock_property_helper.get_icon_at_size.return_value = values["icon"]
+    mock_property_helper.icons = Mock()
+    mock_property_helper.icons.load_icon.return_value = values["icon"]
+    return mock_property_helper    
+
+
 def setup_test_env():
     """ Setup environment suitable for running the test/* code in a checkout.
         This includes PYTHONPATH, sys.path and softwarecenter.paths.datadir.

