#!/usr/bin/env python

import coral
import coral.modeler
import coral.modeler.modeler
from coral.addins.constraint.evaluate import PythonConstraintEvaluator, QueryScriptConstraintEvaluator
import coral.addins.constraint.engine as E

LC = coral.lang.CONSTRAINT10
LU = coral.lang.UML14

######## Testing appliesTo() for PythonConstraints (evaluate.py)
umlPack = LU.Package(name="testPackage")
umlMod = LU.Model(name="testModel")
umlClass = LU.Class(name="testClass")

pcon1 = LC.PythonConstraint(kind=coral.meta.UML14.Class, script="ret = len(self.name)>0")
PC1 = PythonConstraintEvaluator(pcon1)
pcon2 = LC.PythonConstraint(kind=coral.meta.UML14.Package, script="print blabla")
PC2 = PythonConstraintEvaluator(pcon2)

assert PC1.appliesTo(umlClass)
assert not PC1.appliesTo(umlPack)
assert not PC2.appliesTo(umlClass)
assert PC2.appliesTo(umlPack)
assert PC2.appliesTo(umlMod)

######## Testing appliesTo() for QueryScriptConstraints (evaluate.py)
prj = coral.loadDocument("testConstraints.xml")
testTarget = None

for elem in prj.contents():
    if elem.oclIsKindOf(LU.Model) and elem.name == "Target":
        testTarget = elem

QSC = None
for elem in prj.contents():
    if elem.oclIsKindOf(LC.Package):
        for part in elem.__getAllParts__().select(lambda p:p.oclIsKindOf(LC.QueryScriptConstraint)):
            if part.name == "UniqueClassNames":
                QSC = QueryScriptConstraintEvaluator(part)

assert QSC.appliesTo(umlClass)
assert QSC.appliesTo(umlMod)
assert not QSC.appliesTo(umlPack)


######## Testing addResult() and removeResults() from engine.py

testOffending =  None
for o in testTarget.__getAllParts__().select(lambda p:p.oclIsKindOf(LU.Class)):
    if o.name == "differentName":
        testOffending = o

constraintPack = LC.Package(name="constraintPack")
testCM = LC.ConstraintModel(name="testCM", package=constraintPack, target=testTarget)
testRes = LC.Result(name="testResult", constraint=pcon1, constraintmodel=testCM)
testRes.offending.append(testOffending)
testCM.constraint.append(pcon1)

E.addResult(testRes, testCM)
assert len(testCM.result) == 1

E.removeResults(testOffending, pcon1, testCM)
assert len(testCM.result) == 0


######## Testing exceptions

noCompilePCCM = None
noExecutePCCM = None
noCompilePConstr = None
noExecutePConstr = None

noCompileQSCCM = None
noExecuteQSCCM = None
noCompileQSConstr = None
noExecuteQSConstr = None

for elem in prj.contents():
    if elem.oclIsKindOf(LC.Package):
        for part in elem.__getAllParts__().select(lambda p:p.oclIsKindOf(LC.ConstraintModel)):
            if part.name == "ConstraintModel1":
                noCompilePCCM = part
            elif part.name == "ConstraintModel2":
                noExecutePCCM = part
            elif part.name == "ConstraintModel3":
                noCompileQSCCM = part
            elif part.name == "ConstraintModel4":
                noExecuteQSCCM = part
        for part in elem.__getAllParts__().select(lambda p:p.oclIsKindOf(LC.PythonConstraint)):
            if part.name == "NoCompilePC":
                noCompilePConstr = part
            elif part.name == "NoExecutePC":
                noExecutePConstr = part
        for part in elem.__getAllParts__().select(lambda p:p.oclIsKindOf(LC.QueryScriptConstraint)):
            if part.name == "NoCompileQSC":
                noCompileQSConstr = part
            elif part.name == "NoExecuteQSC":
                noExecuteQSConstr = part


eng = E.Engine()
######## A result element is created for the exception of a script that does not compile (PythonConstraint)
assert len(noCompilePCCM.result) == 0
eng.getConstraints(noCompilePCCM, umlClass)
assert len(noCompilePCCM.result) == 1

######## A result element is created for the exception of a script that compiles but is not executable (PythonConstraint)
eng.type2constraintObjects={}
noExecutePC = eng.getConstraints(noExecutePCCM, umlClass)[0]
noExecutePCRes = noExecutePC.searchApply(testTarget)[0]
assert noExecutePCRes.name == "NoExecutePC"

######## A result element is created for the exception of a script that does not compile (QueryScriptConstraint)
assert len(noCompileQSCCM.result) == 0
eng.type2constraintObjects={}
eng.getConstraints(noCompileQSCCM, umlClass)
assert len(noCompileQSCCM.result) == 1

######## A result element is created for the exception of a script that compiles but is not executable (QueryScriptConstraint)
eng.type2constraintObjects={}
noExecuteQSC = eng.getConstraints(noExecuteQSCCM, umlClass)[0]
noExecuteQSCRes = noExecuteQSC.searchApply(noExecuteQSCCM.target)[0]
assert noExecuteQSCRes.name == "NoExecuteQSC"
