有什么方法可以测试我引用 EAttributes 的语法吗?
Is there some way to test my grammar which refer to 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”文件,其中包含一个 class“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, right, e.op)
} else if (e.left.isVariable) {
getVariableReturnsBody(e.left, left, right, e.op)
} else {
getOthersCompareBody(left, right, 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 right, 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 right, 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 right, String operator) {
switch (e) {
VariableRef: {
e.variable.EType.name.equals("EString")
? getStringCompareBody(left, right, operator) : e.variable.EType.name.equals(
"EBoolean") ? getBoolCompareBody(left, right, operator) : getOthersCompareBody(left, right,
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")
)
]
]
我一度陷入困境,因为我无法使用 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”文件,其中包含一个 class“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, right, e.op)
} else if (e.left.isVariable) {
getVariableReturnsBody(e.left, left, right, e.op)
} else {
getOthersCompareBody(left, right, 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 right, 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 right, 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 right, String operator) {
switch (e) {
VariableRef: {
e.variable.EType.name.equals("EString")
? getStringCompareBody(left, right, operator) : e.variable.EType.name.equals(
"EBoolean") ? getBoolCompareBody(left, right, operator) : getOthersCompareBody(left, right,
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")
)
]
]