<commit_before># Case Conductor is a Test Case Management system.
# Copyright (C) 2011-2012 Mozilla
#
# This file is part of Case Conductor.
#
# Case Conductor 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 3 of the License, or
# (at your option) any later version.
#
# Case Conductor 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 Case Conductor.  If not, see <http://www.gnu.org/licenses/>.
"""
Models for test execution (runs, results).

"""
import datetime

from django.core.exceptions import ValidationError
from django.db import connection, models

from model_utils import Choices

from ..ccmodel import CCModel, TeamModel, DraftStatusModel, utcnow
from ..core.auth import User
from ..core.models import ProductVersion
from ..environments.models import Environment, HasEnvironmentsModel
from ..library.models import CaseVersion, Suite, CaseStep, SuiteCase



class Run(CCModel, TeamModel, DraftStatusModel, HasEnvironmentsModel):
    """A test run."""
    productversion = models.ForeignKey(ProductVersion, related_name="runs")
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    start = models.DateField(default=datetime.date.today)
    end = models.DateField(blank=True, null=True)

    caseversions = models.ManyToManyField(
        CaseVersion, through="RunCaseVersion", related_name="runs")
    suites = models.ManyToManyField(
        Suite, through="RunSuite", related_name="runs")


    def __unicode__(self):
        """Return unicode representation."""
        return self.name


    def clean(self):
        """Validate instance field values."""
        if self.end is not None and self.start > self.end:
            raise ValidationError("Start date must be prior to end date.")


    class Meta:
        permissions = [("manage_runs", "Can add/edit/delete test runs.")]


    @property
    def parent(self):
        return self.productversion


    @classmethod
    def cascade_envs_to(cls, objs, adding):
        if adding:
            return {}
        return {RunCaseVersion: RunCaseVersion.objects.filter(run__in=objs)}


    def clone(self, *args, **kwargs):
        """Clone this Run with default cascade behavior."""
        kwargs.setdefault(
            "cascade", ["runsuites", "environments", "team"])
        overrides = kwargs.setdefault("overrides", {})
        overrides["status"] = self.STATUS.draft
        overrides.setdefault("name", "Cloned: {0}".format(self.name))
        return super(Run, self).clone(*args, **kwargs)


    def activate(self, *args, **kwargs):
        """Make run active, locking in runcaseversions for all suites."""
        if self.status == self.STATUS.draft:
            self._lock_case_versions()
        super(Run, self).activate(*args, **kwargs)


    def _lock_case_versions(self):
        """Select caseversions from suites, create runcaseversions."""
        order = 1
        for runsuite in RunSuite.objects.filter(
                run=self).order_by("order").select_related("suite"):
            for suitecase in SuiteCase.objects.filter(
                    suite=runsuite.suite).order_by(
                    "order").select_related("case"):
                try:
                    caseversion = suitecase.case.versions.filter(
                        productversion=self.productversion,
                        status=CaseVersion.STATUS.active).get()
                except CaseVersion.DoesNotExist:
                    pass
                else:
                    envs = _environment_intersection(self, caseversion)
                    if envs:
                        try:
                            rcv = RunCaseVersion.objects.get(
                                run=self, caseversion=caseversion)
                        except RunCaseVersion.MultipleObjectsReturned:
                            dupes = list(
                                RunCaseVersion.objects.filter(
                                    run=self, caseversion=caseversion)
                                )
                            rcv = dupes.pop()
                            for dupe in dupes:
                                rcv.environments.add(*dupe.environments.all())
                                dupe.results.update(runcaseversion=rcv)
                                dupe.delete(permanent=True)
                        except RunCaseVersion.DoesNotExist:
                            rcv = RunCaseVersion(
                                run=self, caseversion=caseversion, order=order)
                            rcv.save(force_insert=True, inherit_envs=False)
                            rcv.environments.add(*envs)
                            order += 1
                        rcv.suites.add(runsuite.suite)


    def result_summary(self):
        """Return a dict summarizing status of results."""
        return result_summary(Result.objects.filter(runcaseversion__run=self))


    def completion(self):<commit_msg>Refactor run-activation to be less nested.<commit_after># Case Conductor is a Test Case Management system.
# Copyright (C) 2011-2012 Mozilla
#
# This file is part of Case Conductor.
#
# Case Conductor 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 3 of the License, or
# (at your option) any later version.
#
# Case Conductor 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 Case Conductor.  If not, see <http://www.gnu.org/licenses/>.
"""
Models for test execution (runs, results).

"""
import datetime

from django.core.exceptions import ValidationError
from django.db import connection, models

from model_utils import Choices

from ..ccmodel import CCModel, TeamModel, DraftStatusModel, utcnow
from ..core.auth import User
from ..core.models import ProductVersion
from ..environments.models import Environment, HasEnvironmentsModel
from ..library.models import CaseVersion, Suite, CaseStep, SuiteCase



class Run(CCModel, TeamModel, DraftStatusModel, HasEnvironmentsModel):
    """A test run."""
    productversion = models.ForeignKey(ProductVersion, related_name="runs")
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    start = models.DateField(default=datetime.date.today)
    end = models.DateField(blank=True, null=True)

    caseversions = models.ManyToManyField(
        CaseVersion, through="RunCaseVersion", related_name="runs")
    suites = models.ManyToManyField(
        Suite, through="RunSuite", related_name="runs")


    def __unicode__(self):
        """Return unicode representation."""
        return self.name


    def clean(self):
        """Validate instance field values."""
        if self.end is not None and self.start > self.end:
            raise ValidationError("Start date must be prior to end date.")


    class Meta:
        permissions = [("manage_runs", "Can add/edit/delete test runs.")]


    @property
    def parent(self):
        return self.productversion


    @classmethod
    def cascade_envs_to(cls, objs, adding):
        if adding:
            return {}
        return {RunCaseVersion: RunCaseVersion.objects.filter(run__in=objs)}


    def clone(self, *args, **kwargs):
        """Clone this Run with default cascade behavior."""
        kwargs.setdefault(
            "cascade", ["runsuites", "environments", "team"])
        overrides = kwargs.setdefault("overrides", {})
        overrides["status"] = self.STATUS.draft
        overrides.setdefault("name", "Cloned: {0}".format(self.name))
        return super(Run, self).clone(*args, **kwargs)


    def activate(self, *args, **kwargs):
        """Make run active, locking in runcaseversions for all suites."""
        if self.status == self.STATUS.draft:
            self._lock_case_versions()
        super(Run, self).activate(*args, **kwargs)


    def _lock_case_versions(self):
        """Select caseversions from suites, create runcaseversions."""
        order = 1
        for runsuite in RunSuite.objects.filter(
                run=self).order_by("order").select_related("suite"):
            for suitecase in SuiteCase.objects.filter(
                    suite=runsuite.suite).order_by(
                    "order").select_related("case"):
                try:
                    caseversion = suitecase.case.versions.filter(
                        productversion=self.productversion,
                        status=CaseVersion.STATUS.active).get()
                except CaseVersion.DoesNotExist:
                    pass
                else:
                    if self._add_caseversion(
                            caseversion, runsuite.suite, order):
                        order += 1


    def _add_caseversion(self, caseversion, suite, order):
        """
        Add given caseversion to this run, from given suite, at given order.

        Returns True if the caseversion was actually added (or found to already
        exist), else False.

        """
        envs = _environment_intersection(self, caseversion)
        if not envs:
            return False
        found = False
        try:
            rcv = RunCaseVersion.objects.get(
                run=self, caseversion=caseversion)
            found = True
        except RunCaseVersion.MultipleObjectsReturned:
            dupes = list(
                RunCaseVersion.objects.filter(
                    run=self, caseversion=caseversion)
                )
            rcv = dupes.pop()
            for dupe in dupes:
                rcv.environments.add(*dupe.environments.all())
                dupe.results.update(runcaseversion=rcv)
                dupe.delete(permanent=True)
            found = True
        except RunCaseVersion.DoesNotExist:
            rcv = RunCaseVersion(
                run=self, caseversion=caseversion, order=order)
            rcv.save(force_insert=True, inherit_envs=False)
            rcv.environments.add(*envs)
        if found:
            rcv.order = order
            rcv.save()
        rcv.suites.add(suite)
        return True


    def result_summary(self):
        """Return a dict summarizing status of results."""
        return result_summary(Result.objects.filter(runcaseversion__run=self))


    def completion(self):
{'fraction_non_alphanumeric': 0.09255016952258774, 'fraction_numerical': 0.0027490149363144875, 'mean_word_length': 2.2755102040816326, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '941499', 'n_tokens_mistral': 2897, 'n_tokens_neox': 2753, 'n_words': 817}