有什么方法可以测试我引用 EAttributes 的语法吗?

问题描述

我一度陷入困境,因为我无法使用 Junit 测试用例来测试我的语法。下面是我完整的语法。

ExpressionModel:
    expression=Expression;

Expression:
    Comparison;

Comparison returns Expression:
    Primary ({Comparison.left=current} op=("=" | "!=" | ">=" | "<=" | ">" | "<")right=Primary)* ;

Primary returns Expression:
    '(' Expression ')' |
    {Not} "!" expression=Primary |
    Atomic;

Atomic returns Expression:
    {IntConstant} value=INT |
    {StringConstant} value=STRING |
    {BoolConstant} value=('true' | 'false') |
    {VariableRef} variable=[ecore::EAttribute|Qualifiedname];

Qualifiedname:
    ID ('.' ID)*;

如果我通过启动一个 eclipse 实例来测试我的代码生成器的这个语法,我所要做的就是在 src 文件夹中创建一个“.ecore”文件和另一个我的语法文件,我可以很容易地访问我的变量在“.ecore”文件中创建。

我的意思是在启动 Eclipse 实例后,我创建了一个“test.ecore”文件,该文件具有一个“vars”类和一个 EString 类型的 EAttribute“alpha”,我创建了另一个文件“testModel.dsl” " 现在我可以轻松访问此文件中的 "vars.alpha"。如果我想在不启动 eclipse 实例的情况下测试我的代码生成器,任何人都可以帮助我如何执行相同的步骤。对我很有帮助。

我正在尝试测试以下测试用例-->

@RunWith(XtextRunner)
@InjectWith(ExtendedMyDslInjectorProvider)
class ExpressionDSLCompilationTest {
@Inject extension CompilationTestHelper
@Inject extension ParseHelper
@Inject extension ReflectExtensions
@Inject extension IQualifiednameProvider
@Inject Provider<XtextResourceSet> resourceSetProvider

@Test
def void ReturnVariable() {

    val fooPackage = EcoreFactory::eINSTANCE.createEPackage
    fooPackage.name = "foo"
    fooPackage.nsprefix = "foo"
    fooPackage.nsURI = "http://foo"

    val fooClass = EcoreFactory::eINSTANCE.createEClass
    fooClass.name = "vars"
    fooPackage.EClassifiers.add(fooClass)

    val fooattr = EcoreFactory::eINSTANCE.createEAttribute
    fooattr.name = "alpha"
    fooattr.EType = EcorePackage::eINSTANCE.EString
    val resourceset = resourceSetProvider.get
    val resource = resourceset.createResource(URI.createURI("hiTest.ecore"))

    fooClass.EStructuralFeatures.add(attr)

    resource.contents.add(fooPackage)
    // val model = '''foo.vars.alpha'''.parse(resourceset)
    '''foo.vars.alpha'''.compile [
        getCompiledClass.newInstance => [
            assertEquals(
                "foo.vars.alpha",it.invoke("generateCodeForExpression")
            )
        ]
    ]
}

class ExtendedMyDslInjectorProvider extends ExpressionDSLInjectorProvider {

    override internalCreateInjector() {
        EcoreSupportStandalonesetup.setup
        return super.internalCreateInjector
    }
}

我已经按照https://www.eclipse.org/forums/index.php/t/1081785/中提到的步骤操作 但这没有用,因为它在我运行测试用例时给了我空指针异常。任何帮助将不胜感激。

我正在添加我的代码生成器的一部分并突出显示出错的部分。希望足够了。

class ExpressionDSLGenerator extends AbstractGenerator {
    @Inject extension IQualifiednameProvider

    /*Generate Java Code with the name of java file as same as that of ".mexpression" file*/
    override void doGenerate(Resource resource,IFileSystemAccess2 fsa,IGeneratorContext context) {
        var str = ""
        for (e : resource.allContents.toIterable.filter(ExpressionModel)) {

            str += e.checkCompileForFunctionsOrExpresssion
        }
        fsa.generateFile('''«resource.URI.lastSegment.substring(0,resource.URI.lastSegment.indexOf("."))».java''',str)
    }

    /*Generates the body of .Java File having class and single checkExpression
     Method for Expressions and Functions Separately */
    def String checkCompileForFunctionsOrExpresssion(ExpressionModel model) {
            '''
public class «model.eResource.URI.lastSegment.substring(0,model.eResource.URI.lastSegment.indexOf("."))»{
    
    public «getExpressionReturnType(model)» generateCodeForExpression() {
        return «getExpressionReturnBody(model.expression)»;
    }
}
'''
        }
    def getExpressionReturnType(ExpressionModel model) {

    /*If expression is not a comparison and just a single variable or value,we must return value's data type*/
        if (model.eContents.size < 2) {
            model.expression.getValueReturnType
        } /* Return boolean since it will be a comparison*/ else {
            "boolean"
        }
    }
    
    // Utility method to get return type of an expression
    def getValueReturnType(Expression e) {
        if (e.isInt) {
            "int"
        } else if (e.isstring) {
            "String"
        } else if (e.isVariable) {
            e.variableReturnsType
        } else {
            "boolean"
        }
    }
    
    // Utility method to set return type on the basis of variable's return type
    def getvariableReturnsType(Expression e) {
        switch (e) {
            VariableRef: {
                <part giving error:-->e.variable.EType is coming to be null,hence null pointer exception>**e.variable.EType.name.equals("EString") ? "String" : e.variable.EType.name.equals(
                    "EInt") ? "int" : "boolean"**</part giving error>
            }
        }
    }
// Utility method to get return body of an expression
    def String getExpressionReturnBody(Expression e) {
        switch (e) {
            VariableRef: {
                getvariableReturn(e.variable)
            }
            IntConstant: {
                e.value.intConstantReturn
            }
            BoolConstant: {
                e.value.booleanConstantReturn
            }
            StringConstant: {
                e.value.stringConstantReturn
            }
            Not: {
                e.expression.notExpressionReturn
            }
            Comparison: {
                val left = e.left.getExpressionReturnBody as String
                val right = e.right.getExpressionReturnBody as String
                if (e.left.isstring) {
                    getStringCompareBody(left,right,e.op)
                } else if (e.left.isBoolean) {
                    getBoolCompareBody(left,e.op)
                } else if (e.left.isVariable) {
                    getvariableReturnsBody(e.left,left,e.op)
                } else {
                    getothersCompareBody(left,e.op)
                }
            }
        }

    }
// return variable's full name 
    def getvariableReturn(EAttribute e) {
        e.fullyQualifiedname + ""
    }
// return integer value
    def getIntConstantReturn(int value) {
        value + ""
    }
// return boolean value
    def getBooleanConstantReturn(String value) {
        Boolean::parseBoolean(value) + ""
    }

    // return string value
    def getStringConstantReturn(String value) {
        "\"" + value + "\""
    }
// return not value of the given expression
    def getNotExpressionReturn(Expression value) {
        "!(" + value.getExpressionReturnBody + ")"
    }
// Utility method to check if Expression is a String
    def isstring(Expression e) {
        switch (e) {
            StringConstant: {
                true
            }
            default: {
                false
            }
        }
    }

    // Utility method to check if Expression is a boolean
    def isBoolean(Expression e) {
        switch (e) {
            BoolConstant: {
                true
            }
            default: {
                false
            }
        }
    }

    // Utility method to check if Expression is a variable
    def isVariable(Expression e) {
        switch (e) {
            VariableRef: {
                true
            }
            default: {
                false
            }
        }
    }
// return body of comparison expression for string
    def getStringCompareBody(String left,String right,String op) {
        switch (op) {
            case '=': "(" + left + ".equals(" + right + "))"
            case '!=': "!(" + left + ".equals(" + right + "))"
            default: false + ""
        }
    }

    // return body of comparison expression for boolean
    def getBoolCompareBody(String left,String op) {
        switch (op) {
            case '=': "(" + left + "==" + right + ")"
            case '!=': "(" + left + "!=" + right + ")"
            default: false + ""
        }
    }

    // return body of comparison expression for other's
    def getothersCompareBody(String left,String op) {
        switch (op) {
            case '<': "(" + left + "<" + right + ")"
            case '>': "(" + left + ">" + right + ")"
            case '>=': "(" + left + ">=" + right + ")"
            case '<=': "(" + left + "<=" + right + ")"
            case '=': "(" + left + "==" + right + ")"
            case '!=': "!(" + left + "==" + right + ")"
            default: false + ""
        }

    }
// body for variable type
    def getvariableReturnsBody(Expression e,String left,String operator) {
        switch (e) {
            VariableRef: {
                e.variable.EType.name.equals("EString")
                    ? getStringCompareBody(left,operator) : e.variable.EType.name.equals(
                    "EBoolean") ? getBoolCompareBody(left,operator) : getothersCompareBody(left,operator)
            }
        }
    }
}

解决方法

@Inject extension ValidationTestHelper h
...
val model = '''foo.vars.alpha'''.parse(resourceset)
model.assertNoErrors

这是论坛片段对您的上下文的适应效果非常好

如果你想使用CompilationTestHelper,那么你必须为resourcetset自定义它以在那里添加资源

例如

val model = '''foo.vars.alpha'''.parse(resourceset)
model.assertNoErrors

compile(resourceset) [
    getCompiledClass.newInstance => [
        assertEquals(
            "foo.vars.alpha",it.invoke("generateCodeForExpression")
        )
    ]
]

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...