[damned-lies] Moved test files as of new Django 1.6 test discovery



commit 5550d9644a6689992ddad3186315612725f7241e
Author: Claude Paroz <claude 2xlibre net>
Date:   Tue Dec 10 08:56:45 2013 +0100

    Moved test files as of new Django 1.6 test discovery
    
    Thanks Marcos Chavarría Teijeiro for noticing this issue.

 languages/{tests/__init__.py => tests.py} |    0
 people/{tests/__init__.py => tests.py}    |    0
 stats/tests/__init__.py                   |  327 +-------------------
 stats/tests/tests.py                      |  325 +++++++++++++++++++
 vertimus/tests/__init__.py                |  502 +----------------------------
 vertimus/tests/tests.py                   |  500 ++++++++++++++++++++++++++++
 6 files changed, 829 insertions(+), 825 deletions(-)
---
diff --git a/languages/tests/__init__.py b/languages/tests.py
similarity index 100%
rename from languages/tests/__init__.py
rename to languages/tests.py
diff --git a/people/tests/__init__.py b/people/tests.py
similarity index 100%
rename from people/tests/__init__.py
rename to people/tests.py
diff --git a/stats/tests/__init__.py b/stats/tests/__init__.py
index df75a35..1ae7f52 100644
--- a/stats/tests/__init__.py
+++ b/stats/tests/__init__.py
@@ -1,325 +1,2 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2008-2012 Claude Paroz <claude 2xlibre net>
-#
-# This file is part of Damned Lies.
-#
-# Damned Lies 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.
-#
-# Damned Lies 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 Damned Lies; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-import os
-import shutil
-import tarfile
-from datetime import date
-
-from django.test import TestCase
-from django.core import mail
-from django.core.exceptions import ValidationError
-from django.core.urlresolvers import reverse
-from django.conf import settings
-
-from stats.models import Module, Domain, Branch, Release, Statistics, FakeLangStatistics
-from stats.utils import check_program_presence, run_shell_command
-from languages.models import Language
-
-from fixture_factory import *
-
-def test_scratchdir(test_func):
-    """ Decorator to temporarily use the scratchdir inside the test directory """
-    def decorator(self):
-        old_SCRATCHDIR = settings.SCRATCHDIR
-        old_POTDIR = settings.POTDIR
-        settings.SCRATCHDIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'scratch')
-        settings.POTDIR = os.path.join(settings.SCRATCHDIR, "POT")
-        os.makedirs(settings.POTDIR)
-        gnome_hello_tar = tarfile.open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 
'gnome-hello.tar.gz'))
-        gnome_hello_tar.extractall(os.path.join(settings.SCRATCHDIR, 'git'))
-        gnome_hello_tar.close()
-        try:
-            test_func(self)
-        finally:
-            shutil.rmtree(settings.SCRATCHDIR)
-            settings.SCRATCHDIR = old_SCRATCHDIR
-            settings.POTDIR = old_POTDIR
-    return decorator
-
-def mocked_checkout(branch):
-    """ Replace real vcs checkout by a mocked method """
-    if branch.name == 'trunk2':
-        raise
-    return
-
-class ModuleTestCase(TestCase):
-    fixtures = ['sample_data.json']
-    SYS_DEPENDENCIES = (
-        ('gettext', 'msgfmt'),
-        ('intltool', 'intltool-update'),
-        ('gnome-doc-utils', 'xml2po'),
-    )
-    def __init__(self, name):
-        TestCase.__init__(self, name)
-        for package, prog in self.SYS_DEPENDENCIES:
-            if not check_program_presence(prog):
-                raise Exception("You are missing a required system package needed by Damned Lies (%s)" % 
package)
-
-    def setUp(self):
-        Branch.checkout_on_creation = False
-        Branch.checkout = mocked_checkout
-        self.mod = Module.objects.get(name="gnome-hello")
-        self.branch = self.mod.branch_set.get(name="master")
-
-    def test_module_methods(self):
-        self.assertEqual(self.mod.get_description(), 'gnome-hello')
-
-    def test_branch_methods(self):
-        self.assertTrue(self.branch.is_head())
-        self.assertEqual(self.branch.get_vcs_url(), "git://git.gnome.org/gnome-hello")
-        self.assertEqual(self.branch.get_vcs_web_url(), "https://git.gnome.org/browse/gnome-hello/";)
-
-    @test_scratchdir
-    def test_branch_stats(self):
-        lang = Language.objects.create(name='xxx', locale='xxx')
-        ghost_stat = Statistics.objects.create(branch=self.branch, 
domain=self.mod.domain_set.get(name='po'), language=lang)
-        # Check stats
-        self.branch.update_stats(force=True)
-        fr_po_stat = Statistics.objects.get(branch=self.branch, domain__name='po', language__locale='fr')
-        self.assertEqual(fr_po_stat.translated(), 44)
-        fr_doc_stat = Statistics.objects.get(branch=self.branch, domain__name='help', language__locale='fr')
-        self.assertEqual(fr_doc_stat.translated(), 13)
-        self.assertEqual(fr_po_stat.po_url(), u"/POT/gnome-hello.master/gnome-hello.master.fr.po")
-        self.assertEqual(fr_po_stat.pot_url(), u"/POT/gnome-hello.master/gnome-hello.master.pot")
-        self.assertEqual(fr_doc_stat.po_url(), u"/POT/gnome-hello.master/docs/gnome-hello-help.master.fr.po")
-        self.assertRaises(Statistics.DoesNotExist, Statistics.objects.get, pk=ghost_stat.pk)
-        from stats.utils import has_toolkit
-        if has_toolkit:
-            self.assertEqual(fr_po_stat.po_url(reduced=True), 
u"/POT/gnome-hello.master/gnome-hello.master.fr.reduced.po")
-            self.assertEqual(fr_po_stat.translated(scope='part'), 44)
-
-    @test_scratchdir
-    def test_delete_branch(self):
-        """ Deleting the master branch of a git module deletes the checkout dir """
-        checkout_path = self.branch.co_path()
-        branch = Branch.objects.create(name="gnome-hello-1-4", module = self.mod)
-        branch.delete()
-        self.assertTrue(os.access(checkout_path, os.F_OK))
-        self.branch.delete()
-        self.assertFalse(os.access(checkout_path, os.F_OK))
-
-    def test_create_unexisting_branch(self):
-        """ Try to create a non-existing branch """
-        Branch.checkout_on_creation = True
-        branch = Branch(name="trunk2",
-                        module = self.mod)
-        self.assertRaises(ValidationError, branch.clean)
-
-    def test_branch_sorting(self):
-        b1 = Branch(name='a-branch', module=self.mod)
-        b1.save(update_statistics=False)
-        b2 = Branch(name='p-branch', module=self.mod)
-        b2.save(update_statistics=False)
-        self.assertEqual([b.name for b in sorted(self.mod.branch_set.all())], 
['master','p-branch','a-branch'])
-        b1.weight = -1
-        b1.save(update_statistics=False)
-        self.assertEqual([b.name for b in sorted(self.mod.branch_set.all())], 
['master','a-branch','p-branch'])
-
-    @test_scratchdir
-    def test_string_frozen_mail(self):
-        """ String change for a module of a string_frozen release should generate a message """
-        mail.outbox = []
-        self.branch.update_stats(force=False)
-
-        # Create a new file with translation
-        new_file_path = os.path.join(self.branch.co_path(), "dummy_file.py")
-        new_string = "Dummy string for D-L tests"
-        f = open(new_file_path, 'w')
-        f.write("a = _('%s')\n" % new_string)
-        f.close()
-        # Add the new file to POTFILES.in
-        f = open(os.path.join(self.branch.co_path(), "po", "POTFILES.in"), 'a')
-        f.write("dummy_file.py\n")
-        f.close()
-        # Regenerate stats (mail should be sent)
-        self.branch.update_stats(force=False, checkout=False)
-        # Assertions
-        self.assertEqual(len(mail.outbox), 1);
-        self.assertEqual(mail.outbox[0].subject, "String additions to 'gnome-hello.master'")
-        self.assertIn('"%s"' % new_string, mail.outbox[0].body)
-
-    def test_read_file_variable(self):
-        from stats.utils import search_variable_in_file
-        file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "help_docbook", "Makefile.am")
-        var_content = search_variable_in_file(file_path, "DOC_INCLUDES")
-        self.assertEqual(var_content.split(), ['rnusers.xml', 'rnlookingforward.xml', '$(NULL)'])
-
-    def test_generate_doc_potfile(self):
-        from stats.utils import generate_doc_pot_file, get_fig_stats, DocFormat
-        # Docbook-style help
-        help_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "help_docbook")
-        potfile, errs, doc_format = generate_doc_pot_file(help_path, 'release-notes', 'release-notes')
-        pot_path = os.path.join(help_path, "C", "release-notes.pot")
-        self.assertTrue(os.access(pot_path, os.R_OK))
-        res = get_fig_stats(pot_path, doc_format=doc_format)
-        self.assertEqual(len(res), 1)
-        os.remove(pot_path)
-        # Mallard-style help (with itstool)
-        pot_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "help_mallard", 
"gnome-help-itstool.pot")
-        res = get_fig_stats(pot_path, doc_format=DocFormat(True, True))
-        self.assertEqual(len(res), 2)
-        self.assertEqual(res[0]['path'], "figures/gnome.png")
-
-    @test_scratchdir
-    def test_http_pot(self):
-        dom = Domain.objects.create(
-            module=self.mod, name='http-po',
-            description='UI Translations', dtype='ui',
-            pot_method='https://l10n.gnome.org/POT/damned-lies.master/damned-lies.master.pot')
-        self.branch.checkout()
-        potfile, errs = dom.generate_pot_file(self.branch)
-        self.assertTrue(os.path.exists(potfile))
-
-    @test_scratchdir
-    def test_dynamic_po(self):
-        """ Test the creation of a blank po file for a new language """
-        lang = Language.objects.create(name="Tamil", locale="ta")
-        self.branch.update_stats(force=False) # At least POT stats needed
-        response = self.client.get('/module/po/gnome-hello/po/master/ta.po')
-        self.assertContains(response, """# Tamil translation for gnome-hello.
-# Copyright (C) %s gnome-hello's COPYRIGHT HOLDER
-# This file is distributed under the same license as the gnome-hello package.
-# FIRST AUTHOR <EMAIL ADDRESS>, YEAR.""" % date.today().year)
-        self.assertContains(response, "Language-Team: Tamil <ta li org>")
-        try:
-            response = self.client.get('/module/po/gnome-hello/po/master/ta-reduced.po')
-        except OSError, e:
-            if "msginit" in str(e):
-                self.fail(
-                    "You are probably running an unpatched version of the translate-toolkit. "
-                    "See http://bugs.locamotion.org/show_bug.cgi?id=2129";
-                )
-                return
-            else:
-                raise e
-        self.assertContains(response, """# Tamil translation for gnome-hello.""")
-
-    @test_scratchdir
-    def test_branch_file_changed(self):
-        # file_hashes is empty in fixture, so first call should always return True
-        self.assertTrue(self.mod.get_head_branch().file_changed("gnome-hello.doap"))
-        self.assertFalse(self.mod.get_head_branch().file_changed("gnome-hello.doap"))
-
-    @test_scratchdir
-    def test_update_maintainers_from_doap_file(self):
-        from stats.doap import update_doap_infos
-        from people.models import Person
-        # Add a maintainer which will be removed
-        pers = Person(username="toto")
-        pers.save()
-        self.mod.maintainers.add(pers)
-        update_doap_infos(self.mod)
-        self.assertEqual(self.mod.maintainers.count(), 3)
-        claude = self.mod.maintainers.get(email='claude 2xlibre net')
-        self.assertEqual(claude.username, 'claudep')
-
-    @test_scratchdir
-    def test_update_doap_infos(self):
-        from stats.doap import update_doap_infos
-        update_doap_infos(self.mod)
-        self.assertEqual(self.mod.homepage, "http://git.gnome.org/browse/gnome-hello";)
-
-
-class StatisticsTests(TestCase):
-    fixtures = ['sample_data.json']
-    def test_total_stats_for_lang(self):
-        rel  = Release.objects.get(name="gnome-2-30")
-        total_for_lang = rel.total_for_lang(Language.objects.get(locale='fr'))
-        self.assertEqual(total_for_lang['ui']['total'], total_for_lang['ui_part']['total'])
-        self.assertTrue(total_for_lang['ui']['untranslated'] == total_for_lang['ui_part']['untranslated'] == 
0)
-        total_for_lang = rel.total_for_lang(Language.objects.get(locale='bem'))
-        self.assertEqual(total_for_lang['ui']['total']-8, total_for_lang['ui_part']['total'])
-        self.assertEqual(total_for_lang['ui']['untranslated'], 183)
-        self.assertEqual(total_for_lang['ui_part']['untranslated'], 175)
-
-    def test_stats_links(self):
-        pot_stats = Statistics.objects.get(
-            branch__module__name='zenity', branch__name='gnome-2-30',
-            domain__name='po', language__isnull=True)
-        self.assertEqual(pot_stats.po_url(), "/POT/zenity.gnome-2-30/zenity.gnome-2-30.pot")
-        stats = Statistics.objects.get(
-            branch__module__name='zenity', branch__name='gnome-2-30',
-            domain__name='po', language__locale='it')
-        self.assertEqual(stats.po_url(), "/POT/zenity.gnome-2-30/zenity.gnome-2-30.it.po")
-        self.assertEqual(stats.po_url(reduced=True), 
"/POT/zenity.gnome-2-30/zenity.gnome-2-30.it.reduced.po")
-        # Same for a fake stats
-        stats = FakeLangStatistics(pot_stats, Language.objects.get(locale='bem'))
-        self.assertEqual(stats.po_url(), "/module/po/zenity/po/gnome-2-30/bem.po")
-        self.assertEqual(stats.po_url(reduced=True), "/module/po/zenity/po/gnome-2-30/bem-reduced.po")
-
-    def test_set_translation_stats(self):
-        from vertimus.models import State, StateTranslating
-        # Get a stat that has full_po and part_po
-        stat = Statistics.objects.get(branch__module__name='zenity', branch__name='gnome-2-30', 
language__locale='it', domain__dtype='ui')
-        pers = Person.objects.create(username="toto")
-        state = StateTranslating.objects.create(branch=stat.branch, domain=stat.domain, 
language=stat.language, person=pers)
-        # Mark file completely translated
-        self.assertNotEqual(stat.part_po, stat.full_po)
-        stat.set_translation_stats('dummy', 136, 0, 0)
-        self.assertEqual(stat.part_po, stat.full_po)
-        # Check state is still translating
-        state = State.objects.filter(branch=stat.branch, domain=stat.domain, language=stat.language)
-        self.assertEqual(len(state), 1)
-        self.assertTrue(isinstance(state[0], StateTranslating))
-
-class FigureTests(TestCase):
-    fixtures = ['sample_data.json']
-    def test_figure_view(self):
-        url = reverse('stats.views.docimages', args=['gnome-hello', 'help', 'master', 'fr'])
-        response = self.client.get(url)
-        self.assertContains(response, "gnome-hello-new.png")
-        # Same for a non-existing language
-        Language.objects.create(name='Afrikaans', locale='af')
-        url = reverse('stats.views.docimages', args=['gnome-hello', 'help', 'master', 'af'])
-        response = self.client.get(url)
-        self.assertContains(response, "gnome-hello-new.png")
-
-    def test_figure_URLs(self):
-        """ Test if figure urls are properly constructed """
-        stat = Statistics.objects.get(branch__module__name='gnome-hello', branch__name='master', 
domain__dtype='doc', language__locale='fr')
-        figs = stat.get_figures()
-        self.assertEqual(figs[0]['orig_remote_url'], 
'https://git.gnome.org/browse/gnome-hello/plain/help/C/figures/gnome-hello-new.png?h=master')
-        self.assertFalse('trans_remote_url' in figs[0])
-
-    @test_scratchdir
-    def test_identical_figure_warning(self):
-        """ Detect warning if translated figure is identical to original figure """
-        from stats.utils import check_identical_figures
-        branch = Branch.objects.get(module__name='gnome-hello', name='master')
-        pot_stat = Statistics.objects.get(branch=branch, domain__name='help', language__isnull=True)
-        fig_path = os.path.join(pot_stat.branch.co_path(), pot_stat.domain.directory, 'C', 
pot_stat.get_figures()[0]['path'])
-        shutil.copyfile(fig_path, fig_path.replace('/C/', '/fr/'))
-        doc_stat = Statistics.objects.get(branch=branch, domain__name='help', language__locale='fr')
-        errs = check_identical_figures(doc_stat.get_figures(), os.path.join(branch.co_path(), 'help'), 'fr')
-        self.assertEqual(len(errs), 1)
-        self.assertTrue(errs[0][1].startswith("Figures should not be copied"))
-
-class OtherTests(TestCase):
-    def test_bugzilla_linkify(self):
-        from stats.templatetags.stats_extras import bugzilla_linkify
-        self.assertEqual(bugzilla_linkify(u"Sample normal text should not be altered."),
-            u"Sample normal text should not be altered.")
-        self.assertEqual(bugzilla_linkify(u"Bugzilla bug numbers like #669240 should be linkified"),
-            u'Bugzilla bug numbers like <a rel="nofollow" 
href="https://bugzilla.gnome.org/show_bug.cgi?id=669240";>#669240</a> should be linkified')
-        self.assertEqual(bugzilla_linkify(u"#669240 start or finish #669240"),
-            u'<a rel="nofollow" href="https://bugzilla.gnome.org/show_bug.cgi?id=669240";>#669240</a> start 
or finish <a rel="nofollow" href="https://bugzilla.gnome.org/show_bug.cgi?id=669240";>#669240</a>')
-        self.assertEqual(bugzilla_linkify(u"Test with encoded entities (rock&#39;n roll) should not."),
-            u"Test with encoded entities (rock&#39;n roll) should not.")
+# Temporary import to accomodate for Django < 1.6
+from .tests import *
diff --git a/stats/tests/tests.py b/stats/tests/tests.py
new file mode 100644
index 0000000..df75a35
--- /dev/null
+++ b/stats/tests/tests.py
@@ -0,0 +1,325 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2008-2012 Claude Paroz <claude 2xlibre net>
+#
+# This file is part of Damned Lies.
+#
+# Damned Lies 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.
+#
+# Damned Lies 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 Damned Lies; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import os
+import shutil
+import tarfile
+from datetime import date
+
+from django.test import TestCase
+from django.core import mail
+from django.core.exceptions import ValidationError
+from django.core.urlresolvers import reverse
+from django.conf import settings
+
+from stats.models import Module, Domain, Branch, Release, Statistics, FakeLangStatistics
+from stats.utils import check_program_presence, run_shell_command
+from languages.models import Language
+
+from fixture_factory import *
+
+def test_scratchdir(test_func):
+    """ Decorator to temporarily use the scratchdir inside the test directory """
+    def decorator(self):
+        old_SCRATCHDIR = settings.SCRATCHDIR
+        old_POTDIR = settings.POTDIR
+        settings.SCRATCHDIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'scratch')
+        settings.POTDIR = os.path.join(settings.SCRATCHDIR, "POT")
+        os.makedirs(settings.POTDIR)
+        gnome_hello_tar = tarfile.open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 
'gnome-hello.tar.gz'))
+        gnome_hello_tar.extractall(os.path.join(settings.SCRATCHDIR, 'git'))
+        gnome_hello_tar.close()
+        try:
+            test_func(self)
+        finally:
+            shutil.rmtree(settings.SCRATCHDIR)
+            settings.SCRATCHDIR = old_SCRATCHDIR
+            settings.POTDIR = old_POTDIR
+    return decorator
+
+def mocked_checkout(branch):
+    """ Replace real vcs checkout by a mocked method """
+    if branch.name == 'trunk2':
+        raise
+    return
+
+class ModuleTestCase(TestCase):
+    fixtures = ['sample_data.json']
+    SYS_DEPENDENCIES = (
+        ('gettext', 'msgfmt'),
+        ('intltool', 'intltool-update'),
+        ('gnome-doc-utils', 'xml2po'),
+    )
+    def __init__(self, name):
+        TestCase.__init__(self, name)
+        for package, prog in self.SYS_DEPENDENCIES:
+            if not check_program_presence(prog):
+                raise Exception("You are missing a required system package needed by Damned Lies (%s)" % 
package)
+
+    def setUp(self):
+        Branch.checkout_on_creation = False
+        Branch.checkout = mocked_checkout
+        self.mod = Module.objects.get(name="gnome-hello")
+        self.branch = self.mod.branch_set.get(name="master")
+
+    def test_module_methods(self):
+        self.assertEqual(self.mod.get_description(), 'gnome-hello')
+
+    def test_branch_methods(self):
+        self.assertTrue(self.branch.is_head())
+        self.assertEqual(self.branch.get_vcs_url(), "git://git.gnome.org/gnome-hello")
+        self.assertEqual(self.branch.get_vcs_web_url(), "https://git.gnome.org/browse/gnome-hello/";)
+
+    @test_scratchdir
+    def test_branch_stats(self):
+        lang = Language.objects.create(name='xxx', locale='xxx')
+        ghost_stat = Statistics.objects.create(branch=self.branch, 
domain=self.mod.domain_set.get(name='po'), language=lang)
+        # Check stats
+        self.branch.update_stats(force=True)
+        fr_po_stat = Statistics.objects.get(branch=self.branch, domain__name='po', language__locale='fr')
+        self.assertEqual(fr_po_stat.translated(), 44)
+        fr_doc_stat = Statistics.objects.get(branch=self.branch, domain__name='help', language__locale='fr')
+        self.assertEqual(fr_doc_stat.translated(), 13)
+        self.assertEqual(fr_po_stat.po_url(), u"/POT/gnome-hello.master/gnome-hello.master.fr.po")
+        self.assertEqual(fr_po_stat.pot_url(), u"/POT/gnome-hello.master/gnome-hello.master.pot")
+        self.assertEqual(fr_doc_stat.po_url(), u"/POT/gnome-hello.master/docs/gnome-hello-help.master.fr.po")
+        self.assertRaises(Statistics.DoesNotExist, Statistics.objects.get, pk=ghost_stat.pk)
+        from stats.utils import has_toolkit
+        if has_toolkit:
+            self.assertEqual(fr_po_stat.po_url(reduced=True), 
u"/POT/gnome-hello.master/gnome-hello.master.fr.reduced.po")
+            self.assertEqual(fr_po_stat.translated(scope='part'), 44)
+
+    @test_scratchdir
+    def test_delete_branch(self):
+        """ Deleting the master branch of a git module deletes the checkout dir """
+        checkout_path = self.branch.co_path()
+        branch = Branch.objects.create(name="gnome-hello-1-4", module = self.mod)
+        branch.delete()
+        self.assertTrue(os.access(checkout_path, os.F_OK))
+        self.branch.delete()
+        self.assertFalse(os.access(checkout_path, os.F_OK))
+
+    def test_create_unexisting_branch(self):
+        """ Try to create a non-existing branch """
+        Branch.checkout_on_creation = True
+        branch = Branch(name="trunk2",
+                        module = self.mod)
+        self.assertRaises(ValidationError, branch.clean)
+
+    def test_branch_sorting(self):
+        b1 = Branch(name='a-branch', module=self.mod)
+        b1.save(update_statistics=False)
+        b2 = Branch(name='p-branch', module=self.mod)
+        b2.save(update_statistics=False)
+        self.assertEqual([b.name for b in sorted(self.mod.branch_set.all())], 
['master','p-branch','a-branch'])
+        b1.weight = -1
+        b1.save(update_statistics=False)
+        self.assertEqual([b.name for b in sorted(self.mod.branch_set.all())], 
['master','a-branch','p-branch'])
+
+    @test_scratchdir
+    def test_string_frozen_mail(self):
+        """ String change for a module of a string_frozen release should generate a message """
+        mail.outbox = []
+        self.branch.update_stats(force=False)
+
+        # Create a new file with translation
+        new_file_path = os.path.join(self.branch.co_path(), "dummy_file.py")
+        new_string = "Dummy string for D-L tests"
+        f = open(new_file_path, 'w')
+        f.write("a = _('%s')\n" % new_string)
+        f.close()
+        # Add the new file to POTFILES.in
+        f = open(os.path.join(self.branch.co_path(), "po", "POTFILES.in"), 'a')
+        f.write("dummy_file.py\n")
+        f.close()
+        # Regenerate stats (mail should be sent)
+        self.branch.update_stats(force=False, checkout=False)
+        # Assertions
+        self.assertEqual(len(mail.outbox), 1);
+        self.assertEqual(mail.outbox[0].subject, "String additions to 'gnome-hello.master'")
+        self.assertIn('"%s"' % new_string, mail.outbox[0].body)
+
+    def test_read_file_variable(self):
+        from stats.utils import search_variable_in_file
+        file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "help_docbook", "Makefile.am")
+        var_content = search_variable_in_file(file_path, "DOC_INCLUDES")
+        self.assertEqual(var_content.split(), ['rnusers.xml', 'rnlookingforward.xml', '$(NULL)'])
+
+    def test_generate_doc_potfile(self):
+        from stats.utils import generate_doc_pot_file, get_fig_stats, DocFormat
+        # Docbook-style help
+        help_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "help_docbook")
+        potfile, errs, doc_format = generate_doc_pot_file(help_path, 'release-notes', 'release-notes')
+        pot_path = os.path.join(help_path, "C", "release-notes.pot")
+        self.assertTrue(os.access(pot_path, os.R_OK))
+        res = get_fig_stats(pot_path, doc_format=doc_format)
+        self.assertEqual(len(res), 1)
+        os.remove(pot_path)
+        # Mallard-style help (with itstool)
+        pot_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "help_mallard", 
"gnome-help-itstool.pot")
+        res = get_fig_stats(pot_path, doc_format=DocFormat(True, True))
+        self.assertEqual(len(res), 2)
+        self.assertEqual(res[0]['path'], "figures/gnome.png")
+
+    @test_scratchdir
+    def test_http_pot(self):
+        dom = Domain.objects.create(
+            module=self.mod, name='http-po',
+            description='UI Translations', dtype='ui',
+            pot_method='https://l10n.gnome.org/POT/damned-lies.master/damned-lies.master.pot')
+        self.branch.checkout()
+        potfile, errs = dom.generate_pot_file(self.branch)
+        self.assertTrue(os.path.exists(potfile))
+
+    @test_scratchdir
+    def test_dynamic_po(self):
+        """ Test the creation of a blank po file for a new language """
+        lang = Language.objects.create(name="Tamil", locale="ta")
+        self.branch.update_stats(force=False) # At least POT stats needed
+        response = self.client.get('/module/po/gnome-hello/po/master/ta.po')
+        self.assertContains(response, """# Tamil translation for gnome-hello.
+# Copyright (C) %s gnome-hello's COPYRIGHT HOLDER
+# This file is distributed under the same license as the gnome-hello package.
+# FIRST AUTHOR <EMAIL ADDRESS>, YEAR.""" % date.today().year)
+        self.assertContains(response, "Language-Team: Tamil <ta li org>")
+        try:
+            response = self.client.get('/module/po/gnome-hello/po/master/ta-reduced.po')
+        except OSError, e:
+            if "msginit" in str(e):
+                self.fail(
+                    "You are probably running an unpatched version of the translate-toolkit. "
+                    "See http://bugs.locamotion.org/show_bug.cgi?id=2129";
+                )
+                return
+            else:
+                raise e
+        self.assertContains(response, """# Tamil translation for gnome-hello.""")
+
+    @test_scratchdir
+    def test_branch_file_changed(self):
+        # file_hashes is empty in fixture, so first call should always return True
+        self.assertTrue(self.mod.get_head_branch().file_changed("gnome-hello.doap"))
+        self.assertFalse(self.mod.get_head_branch().file_changed("gnome-hello.doap"))
+
+    @test_scratchdir
+    def test_update_maintainers_from_doap_file(self):
+        from stats.doap import update_doap_infos
+        from people.models import Person
+        # Add a maintainer which will be removed
+        pers = Person(username="toto")
+        pers.save()
+        self.mod.maintainers.add(pers)
+        update_doap_infos(self.mod)
+        self.assertEqual(self.mod.maintainers.count(), 3)
+        claude = self.mod.maintainers.get(email='claude 2xlibre net')
+        self.assertEqual(claude.username, 'claudep')
+
+    @test_scratchdir
+    def test_update_doap_infos(self):
+        from stats.doap import update_doap_infos
+        update_doap_infos(self.mod)
+        self.assertEqual(self.mod.homepage, "http://git.gnome.org/browse/gnome-hello";)
+
+
+class StatisticsTests(TestCase):
+    fixtures = ['sample_data.json']
+    def test_total_stats_for_lang(self):
+        rel  = Release.objects.get(name="gnome-2-30")
+        total_for_lang = rel.total_for_lang(Language.objects.get(locale='fr'))
+        self.assertEqual(total_for_lang['ui']['total'], total_for_lang['ui_part']['total'])
+        self.assertTrue(total_for_lang['ui']['untranslated'] == total_for_lang['ui_part']['untranslated'] == 
0)
+        total_for_lang = rel.total_for_lang(Language.objects.get(locale='bem'))
+        self.assertEqual(total_for_lang['ui']['total']-8, total_for_lang['ui_part']['total'])
+        self.assertEqual(total_for_lang['ui']['untranslated'], 183)
+        self.assertEqual(total_for_lang['ui_part']['untranslated'], 175)
+
+    def test_stats_links(self):
+        pot_stats = Statistics.objects.get(
+            branch__module__name='zenity', branch__name='gnome-2-30',
+            domain__name='po', language__isnull=True)
+        self.assertEqual(pot_stats.po_url(), "/POT/zenity.gnome-2-30/zenity.gnome-2-30.pot")
+        stats = Statistics.objects.get(
+            branch__module__name='zenity', branch__name='gnome-2-30',
+            domain__name='po', language__locale='it')
+        self.assertEqual(stats.po_url(), "/POT/zenity.gnome-2-30/zenity.gnome-2-30.it.po")
+        self.assertEqual(stats.po_url(reduced=True), 
"/POT/zenity.gnome-2-30/zenity.gnome-2-30.it.reduced.po")
+        # Same for a fake stats
+        stats = FakeLangStatistics(pot_stats, Language.objects.get(locale='bem'))
+        self.assertEqual(stats.po_url(), "/module/po/zenity/po/gnome-2-30/bem.po")
+        self.assertEqual(stats.po_url(reduced=True), "/module/po/zenity/po/gnome-2-30/bem-reduced.po")
+
+    def test_set_translation_stats(self):
+        from vertimus.models import State, StateTranslating
+        # Get a stat that has full_po and part_po
+        stat = Statistics.objects.get(branch__module__name='zenity', branch__name='gnome-2-30', 
language__locale='it', domain__dtype='ui')
+        pers = Person.objects.create(username="toto")
+        state = StateTranslating.objects.create(branch=stat.branch, domain=stat.domain, 
language=stat.language, person=pers)
+        # Mark file completely translated
+        self.assertNotEqual(stat.part_po, stat.full_po)
+        stat.set_translation_stats('dummy', 136, 0, 0)
+        self.assertEqual(stat.part_po, stat.full_po)
+        # Check state is still translating
+        state = State.objects.filter(branch=stat.branch, domain=stat.domain, language=stat.language)
+        self.assertEqual(len(state), 1)
+        self.assertTrue(isinstance(state[0], StateTranslating))
+
+class FigureTests(TestCase):
+    fixtures = ['sample_data.json']
+    def test_figure_view(self):
+        url = reverse('stats.views.docimages', args=['gnome-hello', 'help', 'master', 'fr'])
+        response = self.client.get(url)
+        self.assertContains(response, "gnome-hello-new.png")
+        # Same for a non-existing language
+        Language.objects.create(name='Afrikaans', locale='af')
+        url = reverse('stats.views.docimages', args=['gnome-hello', 'help', 'master', 'af'])
+        response = self.client.get(url)
+        self.assertContains(response, "gnome-hello-new.png")
+
+    def test_figure_URLs(self):
+        """ Test if figure urls are properly constructed """
+        stat = Statistics.objects.get(branch__module__name='gnome-hello', branch__name='master', 
domain__dtype='doc', language__locale='fr')
+        figs = stat.get_figures()
+        self.assertEqual(figs[0]['orig_remote_url'], 
'https://git.gnome.org/browse/gnome-hello/plain/help/C/figures/gnome-hello-new.png?h=master')
+        self.assertFalse('trans_remote_url' in figs[0])
+
+    @test_scratchdir
+    def test_identical_figure_warning(self):
+        """ Detect warning if translated figure is identical to original figure """
+        from stats.utils import check_identical_figures
+        branch = Branch.objects.get(module__name='gnome-hello', name='master')
+        pot_stat = Statistics.objects.get(branch=branch, domain__name='help', language__isnull=True)
+        fig_path = os.path.join(pot_stat.branch.co_path(), pot_stat.domain.directory, 'C', 
pot_stat.get_figures()[0]['path'])
+        shutil.copyfile(fig_path, fig_path.replace('/C/', '/fr/'))
+        doc_stat = Statistics.objects.get(branch=branch, domain__name='help', language__locale='fr')
+        errs = check_identical_figures(doc_stat.get_figures(), os.path.join(branch.co_path(), 'help'), 'fr')
+        self.assertEqual(len(errs), 1)
+        self.assertTrue(errs[0][1].startswith("Figures should not be copied"))
+
+class OtherTests(TestCase):
+    def test_bugzilla_linkify(self):
+        from stats.templatetags.stats_extras import bugzilla_linkify
+        self.assertEqual(bugzilla_linkify(u"Sample normal text should not be altered."),
+            u"Sample normal text should not be altered.")
+        self.assertEqual(bugzilla_linkify(u"Bugzilla bug numbers like #669240 should be linkified"),
+            u'Bugzilla bug numbers like <a rel="nofollow" 
href="https://bugzilla.gnome.org/show_bug.cgi?id=669240";>#669240</a> should be linkified')
+        self.assertEqual(bugzilla_linkify(u"#669240 start or finish #669240"),
+            u'<a rel="nofollow" href="https://bugzilla.gnome.org/show_bug.cgi?id=669240";>#669240</a> start 
or finish <a rel="nofollow" href="https://bugzilla.gnome.org/show_bug.cgi?id=669240";>#669240</a>')
+        self.assertEqual(bugzilla_linkify(u"Test with encoded entities (rock&#39;n roll) should not."),
+            u"Test with encoded entities (rock&#39;n roll) should not.")
diff --git a/vertimus/tests/__init__.py b/vertimus/tests/__init__.py
index 1cd81d3..1ae7f52 100644
--- a/vertimus/tests/__init__.py
+++ b/vertimus/tests/__init__.py
@@ -1,500 +1,2 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2008 Stéphane Raimbault <stephane raimbault gmail com>
-#
-# This file is part of Damned Lies.
-#
-# Damned Lies 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.
-#
-# Damned Lies 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 Damned Lies; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-import os
-
-from django.conf import settings
-from django.core.files.base import File, ContentFile
-from django.core.files.uploadedfile import SimpleUploadedFile
-from django.core import mail
-from django.core.urlresolvers import reverse
-from django.http import QueryDict
-from django.utils.datastructures import MultiValueDict
-
-from teams.tests import TeamsAndRolesTests
-from stats.models import Module, Branch, Release, Category, Domain, Statistics
-from stats.tests import test_scratchdir
-from vertimus.models import *
-from vertimus.forms import ActionForm
-
-class VertimusTest(TeamsAndRolesTests):
-
-    def setUp(self):
-        super(VertimusTest, self).setUp()
-
-        self.m = Module.objects.create(name='gedit', description='GNOME Editor',
-            bugs_base="https://bugzilla.gnome.org/";,
-            bugs_product='gedit', bugs_component='general',
-            vcs_type='svn', vcs_root="http://svn.gnome.org/svn";,
-            vcs_web="http://svn.gnome.org/viewvc/gedit";)
-
-        Branch.checkout_on_creation = False
-        self.b = Branch(name='gnome-2-24', module=self.m)
-        # Block the update of Statistics by the thread
-        self.b.save(update_statistics=False)
-
-        self.r = Release.objects.create(name='gnome-2-24', status='official',
-            description='GNOME 2.24 (stable)',
-            string_frozen=True)
-
-        self.c = Category.objects.create(release=self.r, branch=self.b, name='desktop')
-
-        self.d = Domain.objects.create(module=self.m, name='po',
-            description='UI translations',
-            dtype='ui', directory='po')
-        pot_stat = Statistics.objects.create(language=None, branch=self.b, domain=self.d)
-        self.files_to_clean = []
-
-    def tearDown(self):
-        for path in self.files_to_clean:
-            os.remove(path)
-
-    def test_state_none(self):
-        state = StateNone(branch=self.b, domain=self.d, language=self.l)
-
-        action_names = [a.name for a in state.get_available_actions(self.pn)]
-        self.assertEqual(action_names, ['WC'])
-
-        for p in (self.pt, self.pr):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['RT', 'WC'])
-
-        for p in (self.pc, self.pcoo):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['RT', 'WC', None, 'IC', 'AA'])
-
-    def test_state_translating(self):
-        state = StateTranslating(branch=self.b, domain=self.d, language=self.l, person=self.pt)
-
-        for p in (self.pn, self.pr):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['WC'])
-
-        action_names = [a.name for a in state.get_available_actions(self.pc)]
-        self.assertEqual(action_names, ['WC', None, 'IC', 'AA'])
-
-        action_names = [a.name for a in state.get_available_actions(self.pcoo)]
-        self.assertEqual(action_names, ['WC', 'UNDO', None, 'IC', 'AA'])
-
-        # Same person
-        action_names = [a.name for a in state.get_available_actions(self.pt)]
-        self.assertEqual(action_names, ['UT', 'UNDO', 'WC'])
-
-    def test_state_translated(self):
-        state = StateTranslated(branch=self.b, domain=self.d, language=self.l, person=self.pt)
-
-        action_names = [a.name for a in state.get_available_actions(self.pn)]
-        self.assertEqual(action_names, ['WC'])
-
-        action_names = [a.name for a in state.get_available_actions(self.pt)]
-        self.assertEqual(action_names, ['RT', 'WC'])
-
-        action_names = [a.name for a in state.get_available_actions(self.pr)]
-        self.assertEqual(action_names, ['RP', 'TR', 'RT', 'WC'])
-
-        for p in (self.pc, self.pcoo):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['RP', 'TR', 'RT', 'TC', 'WC', None, 'IC', 'AA'])
-
-    def test_state_proofreading(self):
-        state = StateProofreading(branch=self.b, domain=self.d, language=self.l, person=self.pr)
-
-        for p in (self.pn, self.pt):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['WC'])
-
-        action_names = [a.name for a in state.get_available_actions(self.pc)]
-        self.assertEqual(action_names, ['WC', None, 'IC', 'AA'])
-
-        action_names = [a.name for a in state.get_available_actions(self.pcoo)]
-        self.assertEqual(action_names, ['WC', 'UNDO', None, 'IC', 'AA'])
-
-        # Same person and reviewer
-        action_names = [a.name for a in state.get_available_actions(self.pr)]
-        self.assertEqual(action_names, ['UP', 'TR', 'TC', 'UNDO', 'WC'])
-
-    def test_state_proofread(self):
-        state = StateProofread(branch=self.b, domain=self.d, language=self.l, person=self.pr)
-
-        for p in (self.pn, self.pt):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['WC'])
-
-        action_names = [a.name for a in state.get_available_actions(self.pr)]
-        self.assertEqual(action_names, ['TC', 'RP', 'TR', 'WC'])
-
-        for p in (self.pc, self.pcoo):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['TC', 'RP', 'TR', 'WC', None, 'IC', 'AA'])
-
-    def test_state_to_review(self):
-        state = StateToReview(branch=self.b, domain=self.d, language=self.l, person=self.pt)
-
-        action_names = [a.name for a in state.get_available_actions(self.pn)]
-        self.assertEqual(action_names, ['WC'])
-
-        for p in (self.pt, self.pr):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['RT', 'WC'])
-
-        for p in (self.pc, self.pcoo):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['RT', 'WC', None, 'IC', 'AA'])
-
-    def test_state_to_commit(self):
-        state = StateToCommit(branch=self.b, domain=self.d, language=self.l, person=self.pr)
-
-        for p in (self.pn, self.pt, self.pr):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['WC'])
-
-        for p in (self.pc, self.pcoo):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['RC', 'TR', 'WC', None, 'IC', 'AA'])
-
-    def test_state_committing(self):
-        state = StateCommitting(branch=self.b, domain=self.d, language=self.l, person=self.pc)
-
-        for p in (self.pn, self.pt, self.pr):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['WC'])
-
-        action_names = [a.name for a in state.get_available_actions(self.pcoo)]
-        self.assertEqual(action_names, ['WC', 'UNDO', None, 'IC', 'AA'])
-
-        action_names = [a.name for a in state.get_available_actions(self.pc)]
-        self.assertEqual(action_names, ['IC', 'TR', 'UNDO', 'WC'])
-
-    def test_state_committed(self):
-        state = StateCommitted(branch=self.b, domain=self.d, language=self.l, person=self.pc)
-
-        for p in (self.pn, self.pt, self.pr):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['WC'])
-
-        for p in (self.pc, self.pcoo):
-            action_names = [a.name for a in state.get_available_actions(p)]
-            self.assertEqual(action_names, ['AA', 'WC', None, 'IC', 'AA'])
-
-    def test_action_wc(self):
-        state = StateNone(branch=self.b, domain=self.d, language=self.l)
-        state.save()
-        prev_updated = state.updated
-
-        action = Action.new_by_name('WC', person=self.pt, comment="Hi!")
-        action.apply_on(state, action.send_mail_to_ml)
-        self.assertEqual(len(mail.outbox), 1)
-        self.assertEqual(mail.outbox[0].recipients(), [self.pt.email])
-        # Test that submitting a comment without text generates a validation error
-        form = ActionForm([ActionWC()], True, QueryDict('action=WC&comment='))
-        self.assertTrue("A comment is needed" in str(form.errors))
-        self.assertNotEqual(state.updated, prev_updated)
-
-        # Test send comment to mailing list
-        mail.outbox = []
-        action = Action.new_by_name('WC', person=self.pt, comment="Hi again!")
-        action.apply_on(state, True)
-        self.assertEqual(len(mail.outbox), 1)
-        self.assertEqual(mail.outbox[0].recipients(), [self.l.team.mailing_list])
-        self.assertIn(u"Hi again!", mail.outbox[0].body)
-
-    def test_action_rt(self):
-        state = StateNone(branch=self.b, domain=self.d, language=self.l)
-        state.save()
-
-        action = Action.new_by_name('RT', person=self.pt, comment="Reserved!")
-        action.apply_on(state, action.send_mail_to_ml)
-        self.assertTrue(isinstance(state, StateTranslating))
-
-    @test_scratchdir
-    def test_action_ut(self):
-        # Disabling the role
-        role = Role.objects.get(person=self.pt, team=self.l.team)
-        role.is_active = False
-        role.save()
-
-        state = StateTranslating(branch=self.b, domain=self.d, language=self.l, person=self.pt)
-        state.save()
-
-        test_file = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "valid_po.po"), 'r')
-
-        action = Action.new_by_name('UT', person=self.pt, comment="Done by translator.", 
file=File(test_file))
-        action.apply_on(state, action.send_mail_to_ml)
-
-        self.assertEqual(action.file.url, '/media/upload/gedit-gnome-2-24-po-fr-%d.po' % state.id)
-        self.assertEqual(action.merged_file.url(), '/media/upload/gedit-gnome-2-24-po-fr-%d.merged.po' % 
state.id)
-        # Merged file will not be really produced as no pot file exists on the file system
-        self.files_to_clean.append(action.file.path)
-
-        self.assertTrue(isinstance(state, StateTranslated))
-        # Mail sent to mailing list
-        self.assertEqual(len(mail.outbox), 1)
-        self.assertEqual(mail.outbox[0].recipients(), [self.l.team.mailing_list])
-        self.assertEqual(mail.outbox[0].subject, "gedit - gnome-2-24")
-
-        # Testing if the role was activated
-        role = Role.objects.get(person=self.pt, team=self.l.team)
-        self.assertTrue(role.is_active)
-
-    def test_action_rp(self):
-        state = StateTranslated(branch=self.b, domain=self.d, language=self.l)
-        state.save()
-
-        action = Action.new_by_name('RP', person=self.pr, comment="Reserved by a reviewer!")
-        action.apply_on(state, action.send_mail_to_ml)
-        self.assertTrue(isinstance(state, StateProofreading))
-
-    def test_action_up(self):
-        state = StateProofreading(branch=self.b, domain=self.d, language=self.l, person=self.pr)
-        state.save()
-
-        test_file = ContentFile('test content')
-        test_file.name = 'mytestfile.po'
-
-        action = Action.new_by_name('UP', person=self.pr, comment="Done.", file=test_file)
-        action.apply_on(state, action.send_mail_to_ml)
-        self.files_to_clean.append(action.file.path)
-        self.assertTrue(isinstance(state, StateProofread))
-
-    def test_action_tc(self):
-        state = StateProofread(branch=self.b, domain=self.d, language=self.l)
-        state.save()
-
-        action = Action.new_by_name('TC', person=self.pr, comment="Ready!")
-        action.apply_on(state, action.send_mail_to_ml)
-        self.assertTrue(isinstance(state, StateToCommit))
-
-    def test_action_rc(self):
-        state = StateToCommit(branch=self.b, domain=self.d, language=self.l)
-        state.save()
-
-        action = Action.new_by_name('RC', person=self.pc, comment="This work is mine!")
-        action.apply_on(state, action.send_mail_to_ml)
-        self.assertTrue(isinstance(state, StateCommitting))
-
-    def test_action_ic(self):
-        state = StateProofreading(branch=self.b, domain=self.d, language=self.l, person=self.pr)
-        state.save()
-
-        # Create a new file
-        test_file = ContentFile('test content')
-        test_file.name = 'mytestfile.po'
-
-        action = Action.new_by_name('UP', person=self.pr, comment="Done.", file=test_file)
-        action.apply_on(state, action.send_mail_to_ml)
-        self.assertEqual(len(mail.outbox), 1) # Mail sent to mailing list
-        mail.outbox = []
-
-        file_path = os.path.join(settings.MEDIA_ROOT, action.file.name)
-        self.assertTrue(os.access(file_path, os.W_OK))
-
-        action = Action.new_by_name('TC', person=self.pc, comment="To commit.")
-        action.apply_on(state, action.send_mail_to_ml)
-        self.assertEqual(len(mail.outbox), 1) # Mail sent to committers
-        mail.outbox = []
-
-        action = Action.new_by_name('RC', person=self.pc, comment="Reserved commit.")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('IC', person=self.pc, comment="Committed.")
-        action.apply_on(state, action.send_mail_to_ml)
-        # Mail sent to mailing list
-        self.assertEqual(len(mail.outbox), 1)
-        self.assertEqual(mail.outbox[0].recipients(), [self.l.team.mailing_list])
-        # Team is French (but translations may not be compiled/up-to-date)
-        self.assertTrue(u'Commité' in mail.outbox[0].body or "Committed" in mail.outbox[0].body)
-
-        self.assertTrue(isinstance(state, StateNone))
-        self.assertTrue(not os.access(file_path, os.F_OK), "%s not deleted" % file_path)
-
-        # Remove test file
-        action_archived = ActionArchived.objects.get(comment="Done.")
-        filename_archived = os.path.join(settings.MEDIA_ROOT, action_archived.file.name)
-        action_archived.delete()
-        self.assertTrue(not os.access(filename_archived, os.F_OK), "%s not deleted" % filename_archived)
-
-    def test_action_tr(self):
-        state = StateTranslated(branch=self.b, domain=self.d, language=self.l)
-        state.save()
-
-        action = Action.new_by_name('TR', person=self.pc, comment="Bad work :-/")
-        action.apply_on(state, action.send_mail_to_ml)
-        self.assertTrue(isinstance(state, StateToReview))
-
-    def test_action_aa(self):
-        state = StateCommitted(branch=self.b, domain=self.d, language=self.l, person=self.pr)
-        state.save()
-
-        action = Action.new_by_name('AA', person=self.pc, comment="I don't want to disappear :)")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        state = State.objects.get(branch=self.b, domain=self.d, language=self.l)
-        self.assertTrue(isinstance(state, StateNone))
-        self.assertEqual(state.action_set.count(), 0)
-
-    def test_action_undo(self):
-        state = StateNone(branch=self.b, domain=self.d, language=self.l)
-        state.save()
-
-        action = Action.new_by_name('RT', person=self.pt, comment="Reserved!")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('UNDO', person=self.pt, comment="Ooops! I don't want to do that. Sorry.")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        self.assertEqual(state.name, 'None')
-
-        action = Action.new_by_name('RT', person=self.pt, comment="Translating")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('UT', person=self.pt, comment="Translated")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('RT', person=self.pt, comment="Reserved!")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('UNDO', person=self.pt, comment="Ooops! I don't want to do that. Sorry.")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        self.assertEqual(state.name, 'Translated')
-
-        action = Action.new_by_name('RT', person=self.pt, comment="Translating 1")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('UNDO', person=self.pt, comment="Undo 1")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('RT', person=self.pt, comment="Translating 2")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('UNDO', person=self.pt, comment="Undo 2")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        self.assertEqual(state.name, 'Translated')
-
-    def test_delete(self):
-        """ Test that a whole module tree can be properly deleted """
-        state = StateNone(branch=self.b, domain=self.d, language=self.l)
-        state.save()
-
-        action = Action.new_by_name('WC', person=self.pt, comment="Hi!")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        self.m.delete()
-        self.assertEqual(Action.objects.all().count(), 0)
-
-    def test_delete_domain(self):
-        state = StateTranslating.objects.create(branch=self.b, domain=self.d, language=self.l, 
person=self.pt)
-        self.d.delete()
-        self.assertEqual(State.objects.all().count(), 0)
-
-    def test_delete_statistics(self):
-        """ Test clean_dangling_states receiver """
-        po_stat = Statistics.objects.create(branch=self.b, domain=self.d, language=self.l)
-        state = StateTranslating.objects.create(branch=self.b, domain=self.d, language=self.l, 
person=self.pt)
-        po_stat.delete()
-        self.assertEqual(State.objects.all().count(), 0)
-
-    def test_vertimus_view(self):
-        url = reverse('vertimus_by_ids', args=[self.b.id, self.d.id, self.l.id])
-        response = self.client.get(url)
-        self.assertNotContains(response, '<option value="WC">')
-
-        self.client.login(username=self.pn.username, password='password')
-        response = self.client.get(url)
-        self.assertContains(response, '<option value="WC">')
-
-    def test_uploaded_file_validation(self):
-        # Test a non valid po file
-        post_content = QueryDict('action=WC&comment=Test1')
-        post_file = MultiValueDict({'file': [SimpleUploadedFile('filename.po', 'Not valid po file 
content')]})
-        form = ActionForm([ActionWC()], True, post_content, post_file)
-
-        self.assertTrue('file' in form.errors)
-
-        # Test a valid po file
-        f = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "valid_po.po"), 'r')
-        post_file = MultiValueDict({'file': [File(f)]})
-        form = ActionForm([ActionWC()], True, post_content, post_file)
-        self.assertTrue(form.is_valid())
-
-        # Test form without file
-        form = ActionForm([ActionWC()], True, post_content)
-        self.assertTrue(form.is_valid())
-
-    def test_feeds(self):
-        state = StateNone(branch=self.b, domain=self.d, language=self.l)
-        state.save()
-
-        action = Action.new_by_name('RT', person=self.pt, comment="Translating")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        response = self.client.get(reverse('lang_feed', args=[self.l.locale]))
-        self.assertContains(response,
-            """<rss xmlns:atom="http://www.w3.org/2005/Atom"; version="2.0">""")
-        self.assertContains(response,
-            """<title>po (gedit/User Interface) - gedit (gnome-2-24) - Reserve for translation\n</title>""")
-        self.assertContains(response,
-            """<guid>http://example.com/vertimus/gedit/gnome-2-24/po/fr#%d</guid>""" % action.id)
-
-        response = self.client.get(reverse('team_feed', args=[self.l.team.name]))
-        self.assertContains(response,
-            """<title>po (gedit/User Interface) - gedit (gnome-2-24) - Reserve for translation\n</title>""")
-
-    def test_activity_summary(self):
-        state = StateTranslating.objects.create(
-            branch=self.b, domain=self.d,
-            language=self.l,
-            person=self.pt)
-
-        response = self.client.get(reverse("activity_by_language", args=[self.l.locale]))
-        self.assertContains(response, self.m.description)
-
-    def test_mysql(self):
-        # Copied from test_action_undo() with minor changes
-        state = StateNone(branch=self.b, domain=self.d, language=self.l)
-        state.save()
-
-        action = Action.new_by_name('RT', person=self.pr, comment="Reserved!")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('UNDO', person=self.pr, comment="Ooops! I don't want to do that. Sorry.")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('RT', person=self.pr, comment="Translating")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('UT', person=self.pr, comment="Translated")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('RP', person=self.pr, comment="Proofreading")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        action = Action.new_by_name('UNDO', person=self.pr, comment="Ooops! I don't want to do that. Sorry.")
-        action.apply_on(state, action.send_mail_to_ml)
-
-        actions_db = Action.objects.filter(state_db__id=state.id).exclude(name='WC').order_by('-id')
-
-        # So the last action is UNDO
-        self.assert_(isinstance(actions_db[0], ActionUNDO))
-
-        # Here be dragons! A call to len() workaround the Django/MySQL bug!
-        len(actions_db)
-        self.assert_(isinstance(actions_db[0], ActionUNDO))
+# Temporary import to accomodate for Django < 1.6
+from .tests import *
diff --git a/vertimus/tests/tests.py b/vertimus/tests/tests.py
new file mode 100644
index 0000000..1cd81d3
--- /dev/null
+++ b/vertimus/tests/tests.py
@@ -0,0 +1,500 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2008 Stéphane Raimbault <stephane raimbault gmail com>
+#
+# This file is part of Damned Lies.
+#
+# Damned Lies 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.
+#
+# Damned Lies 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 Damned Lies; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import os
+
+from django.conf import settings
+from django.core.files.base import File, ContentFile
+from django.core.files.uploadedfile import SimpleUploadedFile
+from django.core import mail
+from django.core.urlresolvers import reverse
+from django.http import QueryDict
+from django.utils.datastructures import MultiValueDict
+
+from teams.tests import TeamsAndRolesTests
+from stats.models import Module, Branch, Release, Category, Domain, Statistics
+from stats.tests import test_scratchdir
+from vertimus.models import *
+from vertimus.forms import ActionForm
+
+class VertimusTest(TeamsAndRolesTests):
+
+    def setUp(self):
+        super(VertimusTest, self).setUp()
+
+        self.m = Module.objects.create(name='gedit', description='GNOME Editor',
+            bugs_base="https://bugzilla.gnome.org/";,
+            bugs_product='gedit', bugs_component='general',
+            vcs_type='svn', vcs_root="http://svn.gnome.org/svn";,
+            vcs_web="http://svn.gnome.org/viewvc/gedit";)
+
+        Branch.checkout_on_creation = False
+        self.b = Branch(name='gnome-2-24', module=self.m)
+        # Block the update of Statistics by the thread
+        self.b.save(update_statistics=False)
+
+        self.r = Release.objects.create(name='gnome-2-24', status='official',
+            description='GNOME 2.24 (stable)',
+            string_frozen=True)
+
+        self.c = Category.objects.create(release=self.r, branch=self.b, name='desktop')
+
+        self.d = Domain.objects.create(module=self.m, name='po',
+            description='UI translations',
+            dtype='ui', directory='po')
+        pot_stat = Statistics.objects.create(language=None, branch=self.b, domain=self.d)
+        self.files_to_clean = []
+
+    def tearDown(self):
+        for path in self.files_to_clean:
+            os.remove(path)
+
+    def test_state_none(self):
+        state = StateNone(branch=self.b, domain=self.d, language=self.l)
+
+        action_names = [a.name for a in state.get_available_actions(self.pn)]
+        self.assertEqual(action_names, ['WC'])
+
+        for p in (self.pt, self.pr):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['RT', 'WC'])
+
+        for p in (self.pc, self.pcoo):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['RT', 'WC', None, 'IC', 'AA'])
+
+    def test_state_translating(self):
+        state = StateTranslating(branch=self.b, domain=self.d, language=self.l, person=self.pt)
+
+        for p in (self.pn, self.pr):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['WC'])
+
+        action_names = [a.name for a in state.get_available_actions(self.pc)]
+        self.assertEqual(action_names, ['WC', None, 'IC', 'AA'])
+
+        action_names = [a.name for a in state.get_available_actions(self.pcoo)]
+        self.assertEqual(action_names, ['WC', 'UNDO', None, 'IC', 'AA'])
+
+        # Same person
+        action_names = [a.name for a in state.get_available_actions(self.pt)]
+        self.assertEqual(action_names, ['UT', 'UNDO', 'WC'])
+
+    def test_state_translated(self):
+        state = StateTranslated(branch=self.b, domain=self.d, language=self.l, person=self.pt)
+
+        action_names = [a.name for a in state.get_available_actions(self.pn)]
+        self.assertEqual(action_names, ['WC'])
+
+        action_names = [a.name for a in state.get_available_actions(self.pt)]
+        self.assertEqual(action_names, ['RT', 'WC'])
+
+        action_names = [a.name for a in state.get_available_actions(self.pr)]
+        self.assertEqual(action_names, ['RP', 'TR', 'RT', 'WC'])
+
+        for p in (self.pc, self.pcoo):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['RP', 'TR', 'RT', 'TC', 'WC', None, 'IC', 'AA'])
+
+    def test_state_proofreading(self):
+        state = StateProofreading(branch=self.b, domain=self.d, language=self.l, person=self.pr)
+
+        for p in (self.pn, self.pt):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['WC'])
+
+        action_names = [a.name for a in state.get_available_actions(self.pc)]
+        self.assertEqual(action_names, ['WC', None, 'IC', 'AA'])
+
+        action_names = [a.name for a in state.get_available_actions(self.pcoo)]
+        self.assertEqual(action_names, ['WC', 'UNDO', None, 'IC', 'AA'])
+
+        # Same person and reviewer
+        action_names = [a.name for a in state.get_available_actions(self.pr)]
+        self.assertEqual(action_names, ['UP', 'TR', 'TC', 'UNDO', 'WC'])
+
+    def test_state_proofread(self):
+        state = StateProofread(branch=self.b, domain=self.d, language=self.l, person=self.pr)
+
+        for p in (self.pn, self.pt):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['WC'])
+
+        action_names = [a.name for a in state.get_available_actions(self.pr)]
+        self.assertEqual(action_names, ['TC', 'RP', 'TR', 'WC'])
+
+        for p in (self.pc, self.pcoo):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['TC', 'RP', 'TR', 'WC', None, 'IC', 'AA'])
+
+    def test_state_to_review(self):
+        state = StateToReview(branch=self.b, domain=self.d, language=self.l, person=self.pt)
+
+        action_names = [a.name for a in state.get_available_actions(self.pn)]
+        self.assertEqual(action_names, ['WC'])
+
+        for p in (self.pt, self.pr):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['RT', 'WC'])
+
+        for p in (self.pc, self.pcoo):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['RT', 'WC', None, 'IC', 'AA'])
+
+    def test_state_to_commit(self):
+        state = StateToCommit(branch=self.b, domain=self.d, language=self.l, person=self.pr)
+
+        for p in (self.pn, self.pt, self.pr):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['WC'])
+
+        for p in (self.pc, self.pcoo):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['RC', 'TR', 'WC', None, 'IC', 'AA'])
+
+    def test_state_committing(self):
+        state = StateCommitting(branch=self.b, domain=self.d, language=self.l, person=self.pc)
+
+        for p in (self.pn, self.pt, self.pr):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['WC'])
+
+        action_names = [a.name for a in state.get_available_actions(self.pcoo)]
+        self.assertEqual(action_names, ['WC', 'UNDO', None, 'IC', 'AA'])
+
+        action_names = [a.name for a in state.get_available_actions(self.pc)]
+        self.assertEqual(action_names, ['IC', 'TR', 'UNDO', 'WC'])
+
+    def test_state_committed(self):
+        state = StateCommitted(branch=self.b, domain=self.d, language=self.l, person=self.pc)
+
+        for p in (self.pn, self.pt, self.pr):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['WC'])
+
+        for p in (self.pc, self.pcoo):
+            action_names = [a.name for a in state.get_available_actions(p)]
+            self.assertEqual(action_names, ['AA', 'WC', None, 'IC', 'AA'])
+
+    def test_action_wc(self):
+        state = StateNone(branch=self.b, domain=self.d, language=self.l)
+        state.save()
+        prev_updated = state.updated
+
+        action = Action.new_by_name('WC', person=self.pt, comment="Hi!")
+        action.apply_on(state, action.send_mail_to_ml)
+        self.assertEqual(len(mail.outbox), 1)
+        self.assertEqual(mail.outbox[0].recipients(), [self.pt.email])
+        # Test that submitting a comment without text generates a validation error
+        form = ActionForm([ActionWC()], True, QueryDict('action=WC&comment='))
+        self.assertTrue("A comment is needed" in str(form.errors))
+        self.assertNotEqual(state.updated, prev_updated)
+
+        # Test send comment to mailing list
+        mail.outbox = []
+        action = Action.new_by_name('WC', person=self.pt, comment="Hi again!")
+        action.apply_on(state, True)
+        self.assertEqual(len(mail.outbox), 1)
+        self.assertEqual(mail.outbox[0].recipients(), [self.l.team.mailing_list])
+        self.assertIn(u"Hi again!", mail.outbox[0].body)
+
+    def test_action_rt(self):
+        state = StateNone(branch=self.b, domain=self.d, language=self.l)
+        state.save()
+
+        action = Action.new_by_name('RT', person=self.pt, comment="Reserved!")
+        action.apply_on(state, action.send_mail_to_ml)
+        self.assertTrue(isinstance(state, StateTranslating))
+
+    @test_scratchdir
+    def test_action_ut(self):
+        # Disabling the role
+        role = Role.objects.get(person=self.pt, team=self.l.team)
+        role.is_active = False
+        role.save()
+
+        state = StateTranslating(branch=self.b, domain=self.d, language=self.l, person=self.pt)
+        state.save()
+
+        test_file = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "valid_po.po"), 'r')
+
+        action = Action.new_by_name('UT', person=self.pt, comment="Done by translator.", 
file=File(test_file))
+        action.apply_on(state, action.send_mail_to_ml)
+
+        self.assertEqual(action.file.url, '/media/upload/gedit-gnome-2-24-po-fr-%d.po' % state.id)
+        self.assertEqual(action.merged_file.url(), '/media/upload/gedit-gnome-2-24-po-fr-%d.merged.po' % 
state.id)
+        # Merged file will not be really produced as no pot file exists on the file system
+        self.files_to_clean.append(action.file.path)
+
+        self.assertTrue(isinstance(state, StateTranslated))
+        # Mail sent to mailing list
+        self.assertEqual(len(mail.outbox), 1)
+        self.assertEqual(mail.outbox[0].recipients(), [self.l.team.mailing_list])
+        self.assertEqual(mail.outbox[0].subject, "gedit - gnome-2-24")
+
+        # Testing if the role was activated
+        role = Role.objects.get(person=self.pt, team=self.l.team)
+        self.assertTrue(role.is_active)
+
+    def test_action_rp(self):
+        state = StateTranslated(branch=self.b, domain=self.d, language=self.l)
+        state.save()
+
+        action = Action.new_by_name('RP', person=self.pr, comment="Reserved by a reviewer!")
+        action.apply_on(state, action.send_mail_to_ml)
+        self.assertTrue(isinstance(state, StateProofreading))
+
+    def test_action_up(self):
+        state = StateProofreading(branch=self.b, domain=self.d, language=self.l, person=self.pr)
+        state.save()
+
+        test_file = ContentFile('test content')
+        test_file.name = 'mytestfile.po'
+
+        action = Action.new_by_name('UP', person=self.pr, comment="Done.", file=test_file)
+        action.apply_on(state, action.send_mail_to_ml)
+        self.files_to_clean.append(action.file.path)
+        self.assertTrue(isinstance(state, StateProofread))
+
+    def test_action_tc(self):
+        state = StateProofread(branch=self.b, domain=self.d, language=self.l)
+        state.save()
+
+        action = Action.new_by_name('TC', person=self.pr, comment="Ready!")
+        action.apply_on(state, action.send_mail_to_ml)
+        self.assertTrue(isinstance(state, StateToCommit))
+
+    def test_action_rc(self):
+        state = StateToCommit(branch=self.b, domain=self.d, language=self.l)
+        state.save()
+
+        action = Action.new_by_name('RC', person=self.pc, comment="This work is mine!")
+        action.apply_on(state, action.send_mail_to_ml)
+        self.assertTrue(isinstance(state, StateCommitting))
+
+    def test_action_ic(self):
+        state = StateProofreading(branch=self.b, domain=self.d, language=self.l, person=self.pr)
+        state.save()
+
+        # Create a new file
+        test_file = ContentFile('test content')
+        test_file.name = 'mytestfile.po'
+
+        action = Action.new_by_name('UP', person=self.pr, comment="Done.", file=test_file)
+        action.apply_on(state, action.send_mail_to_ml)
+        self.assertEqual(len(mail.outbox), 1) # Mail sent to mailing list
+        mail.outbox = []
+
+        file_path = os.path.join(settings.MEDIA_ROOT, action.file.name)
+        self.assertTrue(os.access(file_path, os.W_OK))
+
+        action = Action.new_by_name('TC', person=self.pc, comment="To commit.")
+        action.apply_on(state, action.send_mail_to_ml)
+        self.assertEqual(len(mail.outbox), 1) # Mail sent to committers
+        mail.outbox = []
+
+        action = Action.new_by_name('RC', person=self.pc, comment="Reserved commit.")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('IC', person=self.pc, comment="Committed.")
+        action.apply_on(state, action.send_mail_to_ml)
+        # Mail sent to mailing list
+        self.assertEqual(len(mail.outbox), 1)
+        self.assertEqual(mail.outbox[0].recipients(), [self.l.team.mailing_list])
+        # Team is French (but translations may not be compiled/up-to-date)
+        self.assertTrue(u'Commité' in mail.outbox[0].body or "Committed" in mail.outbox[0].body)
+
+        self.assertTrue(isinstance(state, StateNone))
+        self.assertTrue(not os.access(file_path, os.F_OK), "%s not deleted" % file_path)
+
+        # Remove test file
+        action_archived = ActionArchived.objects.get(comment="Done.")
+        filename_archived = os.path.join(settings.MEDIA_ROOT, action_archived.file.name)
+        action_archived.delete()
+        self.assertTrue(not os.access(filename_archived, os.F_OK), "%s not deleted" % filename_archived)
+
+    def test_action_tr(self):
+        state = StateTranslated(branch=self.b, domain=self.d, language=self.l)
+        state.save()
+
+        action = Action.new_by_name('TR', person=self.pc, comment="Bad work :-/")
+        action.apply_on(state, action.send_mail_to_ml)
+        self.assertTrue(isinstance(state, StateToReview))
+
+    def test_action_aa(self):
+        state = StateCommitted(branch=self.b, domain=self.d, language=self.l, person=self.pr)
+        state.save()
+
+        action = Action.new_by_name('AA', person=self.pc, comment="I don't want to disappear :)")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        state = State.objects.get(branch=self.b, domain=self.d, language=self.l)
+        self.assertTrue(isinstance(state, StateNone))
+        self.assertEqual(state.action_set.count(), 0)
+
+    def test_action_undo(self):
+        state = StateNone(branch=self.b, domain=self.d, language=self.l)
+        state.save()
+
+        action = Action.new_by_name('RT', person=self.pt, comment="Reserved!")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('UNDO', person=self.pt, comment="Ooops! I don't want to do that. Sorry.")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        self.assertEqual(state.name, 'None')
+
+        action = Action.new_by_name('RT', person=self.pt, comment="Translating")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('UT', person=self.pt, comment="Translated")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('RT', person=self.pt, comment="Reserved!")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('UNDO', person=self.pt, comment="Ooops! I don't want to do that. Sorry.")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        self.assertEqual(state.name, 'Translated')
+
+        action = Action.new_by_name('RT', person=self.pt, comment="Translating 1")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('UNDO', person=self.pt, comment="Undo 1")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('RT', person=self.pt, comment="Translating 2")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('UNDO', person=self.pt, comment="Undo 2")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        self.assertEqual(state.name, 'Translated')
+
+    def test_delete(self):
+        """ Test that a whole module tree can be properly deleted """
+        state = StateNone(branch=self.b, domain=self.d, language=self.l)
+        state.save()
+
+        action = Action.new_by_name('WC', person=self.pt, comment="Hi!")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        self.m.delete()
+        self.assertEqual(Action.objects.all().count(), 0)
+
+    def test_delete_domain(self):
+        state = StateTranslating.objects.create(branch=self.b, domain=self.d, language=self.l, 
person=self.pt)
+        self.d.delete()
+        self.assertEqual(State.objects.all().count(), 0)
+
+    def test_delete_statistics(self):
+        """ Test clean_dangling_states receiver """
+        po_stat = Statistics.objects.create(branch=self.b, domain=self.d, language=self.l)
+        state = StateTranslating.objects.create(branch=self.b, domain=self.d, language=self.l, 
person=self.pt)
+        po_stat.delete()
+        self.assertEqual(State.objects.all().count(), 0)
+
+    def test_vertimus_view(self):
+        url = reverse('vertimus_by_ids', args=[self.b.id, self.d.id, self.l.id])
+        response = self.client.get(url)
+        self.assertNotContains(response, '<option value="WC">')
+
+        self.client.login(username=self.pn.username, password='password')
+        response = self.client.get(url)
+        self.assertContains(response, '<option value="WC">')
+
+    def test_uploaded_file_validation(self):
+        # Test a non valid po file
+        post_content = QueryDict('action=WC&comment=Test1')
+        post_file = MultiValueDict({'file': [SimpleUploadedFile('filename.po', 'Not valid po file 
content')]})
+        form = ActionForm([ActionWC()], True, post_content, post_file)
+
+        self.assertTrue('file' in form.errors)
+
+        # Test a valid po file
+        f = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "valid_po.po"), 'r')
+        post_file = MultiValueDict({'file': [File(f)]})
+        form = ActionForm([ActionWC()], True, post_content, post_file)
+        self.assertTrue(form.is_valid())
+
+        # Test form without file
+        form = ActionForm([ActionWC()], True, post_content)
+        self.assertTrue(form.is_valid())
+
+    def test_feeds(self):
+        state = StateNone(branch=self.b, domain=self.d, language=self.l)
+        state.save()
+
+        action = Action.new_by_name('RT', person=self.pt, comment="Translating")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        response = self.client.get(reverse('lang_feed', args=[self.l.locale]))
+        self.assertContains(response,
+            """<rss xmlns:atom="http://www.w3.org/2005/Atom"; version="2.0">""")
+        self.assertContains(response,
+            """<title>po (gedit/User Interface) - gedit (gnome-2-24) - Reserve for translation\n</title>""")
+        self.assertContains(response,
+            """<guid>http://example.com/vertimus/gedit/gnome-2-24/po/fr#%d</guid>""" % action.id)
+
+        response = self.client.get(reverse('team_feed', args=[self.l.team.name]))
+        self.assertContains(response,
+            """<title>po (gedit/User Interface) - gedit (gnome-2-24) - Reserve for translation\n</title>""")
+
+    def test_activity_summary(self):
+        state = StateTranslating.objects.create(
+            branch=self.b, domain=self.d,
+            language=self.l,
+            person=self.pt)
+
+        response = self.client.get(reverse("activity_by_language", args=[self.l.locale]))
+        self.assertContains(response, self.m.description)
+
+    def test_mysql(self):
+        # Copied from test_action_undo() with minor changes
+        state = StateNone(branch=self.b, domain=self.d, language=self.l)
+        state.save()
+
+        action = Action.new_by_name('RT', person=self.pr, comment="Reserved!")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('UNDO', person=self.pr, comment="Ooops! I don't want to do that. Sorry.")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('RT', person=self.pr, comment="Translating")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('UT', person=self.pr, comment="Translated")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('RP', person=self.pr, comment="Proofreading")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        action = Action.new_by_name('UNDO', person=self.pr, comment="Ooops! I don't want to do that. Sorry.")
+        action.apply_on(state, action.send_mail_to_ml)
+
+        actions_db = Action.objects.filter(state_db__id=state.id).exclude(name='WC').order_by('-id')
+
+        # So the last action is UNDO
+        self.assert_(isinstance(actions_db[0], ActionUNDO))
+
+        # Here be dragons! A call to len() workaround the Django/MySQL bug!
+        len(actions_db)
+        self.assert_(isinstance(actions_db[0], ActionUNDO))


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]