Skip to content

Commit

Permalink
[testGeneration] Fixing platform specific tests for Umple model/ignor…
Browse files Browse the repository at this point in the history
…eing unrelated targeted tests. In addition to adding a generic mechanism to write test template for elements such as attribute/method/association. This is done by declaring non-specific test as 'generic' and pass the type of Umple element you want to generically generate your test template for using <<elementType>> as a generic attribute within the test case. This aims to target large number of elements in big models and cut time/cost, also to over come some limitations of the language, in case a developer wants to write their own templates.. The type of element to be targeted for generic test generation will be narrowed down with parameters, for instance, one can write any number of test template for all attributes of type String and for method, it would be by declaring element:method and indicating the type of parameters and returned value. .details in usermanual will be provided soon
  • Loading branch information
SultanEid committed Oct 2, 2019
1 parent c614672 commit 14730f1
Show file tree
Hide file tree
Showing 12 changed files with 327 additions and 6 deletions.
18 changes: 17 additions & 1 deletion UmpleTToJunit/UmpleTLTemplates/members_AllTestCases.ump
Expand Up @@ -6,8 +6,22 @@ class UmpleTToJUnit {


members_AllTestCases <<!<</*members_AllTestCases*/>><<# members_AllTestCases <<!<</*members_AllTestCases*/>><<#


boolean skipTest = false;
boolean isConcrete = false;
for (TestCase tc : model.getTestSuite(0).getTestcases()) for (TestCase tc : model.getTestSuite(0).getTestcases())
{#>> {if (tc.getIsTargeted())
{
if(tc.getConcreteLanguage().equals( "PhpUnit") || tc.getConcreteLanguage().equals("RubyUnit") )
{
skipTest = true;
}
}


if (skipTest) {
//skipThisTest
}
else{ #>>
@Test @Test
public void <<=tc.getName() >>() public void <<=tc.getName() >>()
{ {
Expand Down Expand Up @@ -65,6 +79,8 @@ for (TestCase tc : model.getTestSuite(0).getTestcases())
<<# <<#
} }


skipTest = false;
}


#>>!>> #>>!>>
} }
22 changes: 21 additions & 1 deletion UmpleTToPhpUnit/UmpleTLTemplates/members_AllTestCases.ump
Expand Up @@ -6,8 +6,25 @@ class UmpleTToPhpUnit {


members_AllTestCases <<!<</*members_AllTestCases*/>><<# members_AllTestCases <<!<</*members_AllTestCases*/>><<#


boolean skipTest = false;
boolean isConcrete = false;
for (TestCase tc : model.getTestSuite(0).getTestcases()) for (TestCase tc : model.getTestSuite(0).getTestcases())
{#>> {
if (tc.getIsTargeted())
{
if(tc.getConcreteLanguage().equals( "JUnit") || tc.getConcreteLanguage().equals("RubyUnit") )
{
skipTest = true;
}
}


if (skipTest) {
//skipThisTest
}
else{

#>>
public function <<=tc.getName() >>() public function <<=tc.getName() >>()
{ {
<<# <<#
Expand Down Expand Up @@ -66,5 +83,8 @@ for (TestCase tc : model.getTestSuite(0).getTestcases())
} }




skipTest = false;
}

#>>!>> #>>!>>
} }
24 changes: 23 additions & 1 deletion UmpleTToRubyUnit/UmpleTLTemplates/members_AllTestCases.ump
Expand Up @@ -6,8 +6,27 @@ class UmpleTToRubyUnit {


members_AllTestCases <<!<</*members_AllTestCases*/>><<# members_AllTestCases <<!<</*members_AllTestCases*/>><<#



boolean skipTest = false;
boolean isConcrete = false;

for (TestCase tc : model.getTestSuite(0).getTestcases()) for (TestCase tc : model.getTestSuite(0).getTestcases())
{#>> {
if (tc.getIsTargeted())
{
if(tc.getConcreteLanguage().equals( "PhpUnit") || tc.getConcreteLanguage().equals("JUnit") )
{
skipTest = true;
}
}


if (skipTest) {
//skipThisTest
}
else{

#>>
def <<=tc.getName() >> < Test::Unitt::TestCase def <<=tc.getName() >> < Test::Unitt::TestCase
<<# <<#
for (int i = 0; i<tc.getLocOrder();i++) for (int i = 0; i<tc.getLocOrder();i++)
Expand Down Expand Up @@ -72,5 +91,8 @@ for (TestCase tc : model.getTestSuite(0).getTestcases())
} }




skipTest = false;
}

#>>!>> #>>!>>
} }
4 changes: 3 additions & 1 deletion cruise.umple.test-parser/src/ump/TestCaseTemplate_model.ump
Expand Up @@ -51,7 +51,9 @@ class TestCase {


name; name;
int locOrder; int locOrder;

String concreteLanguage = "";
boolean isTargeted = false;
boolean isConcrete = false;


0..1 testcase -- * TestInitialization inits; 0..1 testcase -- * TestInitialization inits;
0..1 testcase -- * Assertion assertions; 0..1 testcase -- * Assertion assertions;
Expand Down
25 changes: 25 additions & 0 deletions cruise.umple.test-parser/src/ump/mbt_parser_src.ump
Expand Up @@ -467,6 +467,31 @@ for ( Token st : t.getSubTokens())


{ {


if(st.getName().equals("isTargeted"))
{
if(st.getValue("isTargeted") != null)
{

aTestCase.setIsTargeted(true);
aTestCase.setConcreteLanguage(st.getValue("isTargeted"));
System.out.println( aTestCase.getConcreteLanguage());

}


}

if(st.getName().equals("isConcrete"))
{
if(st.getValue("isConcrete") != null)
{
aTestCase.setIsConcrete(true);
aTestCase.setIsTargeted(true);
aTestCase.setConcreteLanguage(st.getValue("isTargeted"));
}

}

if(st.getName().equals("initialization")) if(st.getName().equals("initialization"))
{ {
//system.out.println("\tInitlocOrder"); //system.out.println("\tInitlocOrder");
Expand Down
2 changes: 1 addition & 1 deletion cruise.umple.test-parser/src/ump/mbt_parsing.grammar
Expand Up @@ -25,7 +25,7 @@ thenCont: (THEN:)? [[testCase]]*




//testCase : test [~testCaseName] {( [[initialization]] | [[methodCall]] | [[assertions]] | [[testInitAtt]] | [[comment]] )* } //testCase : test [~testCaseName] {( [[initialization]] | [[methodCall]] | [[assertions]] | [[testInitAtt]] | [[comment]] )* }
testCase : test [~testCaseName] {( [[initialization]] | [[assertion]] | [[testInitAtt]] | [[comment]] )* } testCase : [=abstract:abstract]? [=isConcrete:concrete]? [=isTargeted:JUnit|PhpUnit|RubyUnit]? test [~testCaseName] {( [[initialization]] | [[assertion]] | [[testInitAtt]] | [[comment]] )* }
initialization : [~identifier] [~name] OPEN_ROUND_BRACKET [[parameter]]* CLOSE_ROUND_BRACKET ; initialization : [~identifier] [~name] OPEN_ROUND_BRACKET [[parameter]]* CLOSE_ROUND_BRACKET ;
//testinitAtt //testinitAtt
testInitAtt : [~identifier] [~attributeName] = [[pValue]] ; testInitAtt : [~identifier] [~attributeName] = [[pValue]] ;
Expand Down
5 changes: 5 additions & 0 deletions cruise.umple/src/UmpleInternalParser_CodeClass.ump
Expand Up @@ -320,6 +320,11 @@ class UmpleInternalParser
analyzeClassTestCase(token,aClass); analyzeClassTestCase(token,aClass);
} }


else if (token.is("genericTestCase"))
{
analyzeClassGenericTestCase(token,aClass);
}

else if (token.is("testSequence")) else if (token.is("testSequence"))
{ {
analyzeClassTestSequence(token,aClass); analyzeClassTestSequence(token,aClass);
Expand Down
97 changes: 97 additions & 0 deletions cruise.umple/src/UmpleInternalParser_CodeTest.ump
Expand Up @@ -975,6 +975,103 @@ private void analyzeClassTestSequence(Token token, UmpleClass aClass) {


} }


///// generic methods

private void analyzeClassGenericTestCase(Token token, UmpleClass aClass){
String element = "";

if (token.getValue("genericElement").equals("attribute"))
{
element = "attribute";
}

else if (token.getValue("genericElement").equals("method"))
{
element = "method";
}

else {
getParseResult().addErrorMessage(new ErrorMessage(new ErrorType(6020,4, "Generic Test element is not recognized. ", ""), aClass.getPosition(0)));
}




if (element.equals("attribute"))
{
for (Attribute att : aClass.getAttributes())
{
String code = token.getValue("code");
//boolean isPascaled = false;
char preChar = '-';
int indexOfNonPascaledElement = 0;
int preCharIndex = 0;
//StringBuilder code = new StringBuilder(token.getValue("code"));
String pascalRegex = "[a-zA-Z0-9]<<attribute>>";
String nonPascalRegex = "[=|(|!|\\s]<<attribute>>";
//String lookAheadAssertion = "\\w(?= {attribute})";
Pattern pattern = Pattern.compile(pascalRegex);
Matcher matcher = pattern.matcher(code);
Pattern nonPattern = Pattern.compile(nonPascalRegex);
Matcher nonMatcher =nonPattern.matcher(code);
//preChar = code.substring(matcher.start()-2, matcher.start()-1).;
while(matcher.find())
{
int startIndex = matcher.start();
int endIndex = matcher.end();
preCharIndex = matcher.start();
preChar = code.charAt(preCharIndex);
if(Character.isLetter(preChar)){ // to check that the attribute is within a method call such as getId and has no white spaces or Java characters: ex get<<attribute>>
String tempGroup = matcher.group();
String tempReplacement = tempGroup.replace("<<attribute>>", StringFormatter.toPascalCase(att.getName()));
code = code.replace(tempGroup,tempReplacement);
}
while (nonMatcher.find()) // this loop fins matches of attribute that are not part of a methodCall example : getValue(<<attribute>>) it is rather a parameter in this case or String tempAtt = <<attribute>>
{
String tempGroup = nonMatcher.group();
String tempReplacement = tempGroup.replace("<<attribute>>", att.getName());
code = code.replace(tempGroup,tempReplacement);
}

//isPascaled = false;

}

//System.out.println(code);

UmpleTestCase uTestCase = new UmpleTestCase(token.getValue("testCaseName")+"_"+att.getName(),0);
TestAction aTestAction = new TestAction("genericAttribute", code.toString(), "generic", 0);

uTestCase.addTestAction(aTestAction);
uTestCase.setLocOrder(uTestCase.getLocOrder()+1);
aClass.addUmpleTestCase(uTestCase);
matcher.reset();

//System.out.println(uTestCase.getTestAction(0).getActionCode());
}




}



if (element.equals("method"))
{
for (Method meth : aClass.getMethods())
{
UmpleTestCase uTestCase = new UmpleTestCase(token.getValue("testCaseName")+"_"+meth.getName(),0);
TestAction aTestAction = new TestAction("genericAttribute", token.getValue("code"), "generic", 0);
aTestAction.setActionCode(aTestAction.getActionCode().replace("{method}", meth.getName()));
uTestCase.addTestAction(aTestAction);
uTestCase.setLocOrder(uTestCase.getLocOrder()+1);
aClass.addUmpleTestCase(uTestCase);
}
}
}








Expand Down
5 changes: 4 additions & 1 deletion cruise.umple/src/umple_classes.grammar
Expand Up @@ -29,7 +29,7 @@ associationClassDefinition : associationClass [name] { [[associationClassContent
enumerationDefinition : enum [name] { [enumValue](, [enumValue])* } enumerationDefinition : enum [name] { [enumValue](, [enumValue])* }


// The following items can be found inside the body of classes or association classes // The following items can be found inside the body of classes or association classes
classContent- : [[comment]] | [[innerClass]] | [[mixsetDefinition]] | [[distributable]] | [[proxyPattern]] | [[classDefinition]] | [[trace]] | [[emitMethod]] | [[templateAttributeDefinition]] | [[primitiveDefinition]] | [[portDefinition]] | [[portBindingDefinition]] | [[position]] | [[displayColor]] | [[abstract]] | [[keyDefinition]] | [[softwarePattern]] | [[depend]] | [[symmetricReflexiveAssociation]] | [[attribute]] | [[testCase]] | [[testSequence]] | [[stateMachine]] | [[activeMethodDefinition]] | [[inlineAssociation]] | [[concreteMethodDeclaration]] | [[constantDeclaration]] | [[modelConstraint]] | [[invariant]] | ; | [[enumerationDefinition]] | [[exception]] | [[extraCode]] classContent- : [[comment]] | [[innerClass]] | [[mixsetDefinition]] | [[distributable]] | [[proxyPattern]] | [[classDefinition]] | [[trace]] | [[emitMethod]] | [[templateAttributeDefinition]] | [[primitiveDefinition]] | [[portDefinition]] | [[portBindingDefinition]] | [[position]] | [[displayColor]] | [[abstract]] | [[keyDefinition]] | [[softwarePattern]] | [[depend]] | [[symmetricReflexiveAssociation]] | [[attribute]] | [[testCase]] | [[genericTestCase]] | [[testSequence]] | [[stateMachine]] | [[activeMethodDefinition]] | [[inlineAssociation]] | [[concreteMethodDeclaration]] | [[constantDeclaration]] | [[modelConstraint]] | [[invariant]] | ; | [[enumerationDefinition]] | [[exception]] | [[extraCode]]
associationClassContent- : [[comment]] | [[classDefinition]] | [[position]] | [[displayColor]] | [[invariant]] | [[softwarePattern]] | [[depend]] | [[association]] | [[inlineAssociation]] | [[singleAssociationEnd]] | [[attribute]] | [[stateMachine]] | ; | [[extraCode]] associationClassContent- : [[comment]] | [[classDefinition]] | [[position]] | [[displayColor]] | [[invariant]] | [[softwarePattern]] | [[depend]] | [[association]] | [[inlineAssociation]] | [[singleAssociationEnd]] | [[attribute]] | [[stateMachine]] | ; | [[extraCode]]
innerClass : [[innerStaticClass]] | [[innerNonStaticClass]] innerClass : [[innerStaticClass]] | [[innerNonStaticClass]]
innerStaticClass : static [[classDefinition]] innerStaticClass : static [[classDefinition]]
Expand Down Expand Up @@ -81,6 +81,9 @@ interfaceTest : test [~testName] ;
testSequence : testSequence [~sequenceName] { [[testSequenceEntry]] } testSequence : testSequence [~sequenceName] { [[testSequenceEntry]] }
testSequenceEntry : [~name] ( -> [~name] )* ; testSequenceEntry : [~name] ( -> [~name] )* ;


// Generic test case rules
genericTestCase : generic test [~testCaseName] OPEN_ROUND_BRACKET [~genericElement] CLOSE_ROUND_BRACKET { ( [**code] )* }







Expand Down
@@ -0,0 +1,25 @@

class Person {

id;
name;
address;


generic test checkifLogged(attribute){
Person p1 ( "S1425", "John", "Ottawa") ;
String valueToCheck = p1.get<<attribute>>();
ps1.getValue(<<attribute>>);
boolean isLogged = p1.checkIsLogged(valueToCheck);
assertTrue(logged == "true");
}





String returnSumOfValues (int x, int y) { return x+y;}

}


Expand Up @@ -310,6 +310,18 @@ public void testSequence_noTestCasesTest()


} }


@Test
public void genericTestCaseTest()
{
language = "Test";
assertUmpleTemplateFor("test/GenericTestCase.ump","test/testGenericTestCase.test.txt");
//Assert.assertEquals(true, (new File(pathToInput + "/test/test/NNToManyAssociation_ModelTest.umpt")).exists());
createUmpleSystem(pathToInput, "test/GenericTestCase.ump");
Assert.assertEquals(true, (new File(pathToInput + "/test/test/GenericTestCase_ModelTest.umpt")).exists());


}







Expand Down

0 comments on commit 14730f1

Please sign in to comment.