From 14730f1dcaf7ea726841ff428f2a2806d59d3e95 Mon Sep 17 00:00:00 2001 From: Sultan Almaghthawi Date: Tue, 1 Oct 2019 23:50:30 -0400 Subject: [PATCH] [testGeneration] Fixing platform specific tests for Umple model/ignoreing 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 <> 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 --- .../UmpleTLTemplates/members_AllTestCases.ump | 18 +++- .../UmpleTLTemplates/members_AllTestCases.ump | 22 ++++- .../UmpleTLTemplates/members_AllTestCases.ump | 24 ++++- .../src/ump/TestCaseTemplate_model.ump | 4 +- .../src/ump/mbt_parser_src.ump | 25 +++++ .../src/ump/mbt_parsing.grammar | 2 +- .../src/UmpleInternalParser_CodeClass.ump | 5 + .../src/UmpleInternalParser_CodeTest.ump | 97 +++++++++++++++++++ cruise.umple/src/umple_classes.grammar | 5 +- .../implementation/test/GenericTestCase.ump | 25 +++++ .../implementation/test/TestTemplateTest.java | 12 +++ .../test/testGenericTestcase.test.txt | 94 ++++++++++++++++++ 12 files changed, 327 insertions(+), 6 deletions(-) create mode 100644 cruise.umple/test/cruise/umple/implementation/test/GenericTestCase.ump create mode 100644 cruise.umple/test/cruise/umple/implementation/test/testGenericTestcase.test.txt diff --git a/UmpleTToJunit/UmpleTLTemplates/members_AllTestCases.ump b/UmpleTToJunit/UmpleTLTemplates/members_AllTestCases.ump index b8100f39a5..f385772e34 100644 --- a/UmpleTToJunit/UmpleTLTemplates/members_AllTestCases.ump +++ b/UmpleTToJunit/UmpleTLTemplates/members_AllTestCases.ump @@ -6,8 +6,22 @@ class UmpleTToJUnit { members_AllTestCases <><<# +boolean skipTest = false; +boolean isConcrete = false; 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 public void <<=tc.getName() >>() { @@ -65,6 +79,8 @@ for (TestCase tc : model.getTestSuite(0).getTestcases()) <<# } +skipTest = false; +} #>>!>> } \ No newline at end of file diff --git a/UmpleTToPhpUnit/UmpleTLTemplates/members_AllTestCases.ump b/UmpleTToPhpUnit/UmpleTLTemplates/members_AllTestCases.ump index 67d2b73bba..0232ff29f5 100644 --- a/UmpleTToPhpUnit/UmpleTLTemplates/members_AllTestCases.ump +++ b/UmpleTToPhpUnit/UmpleTLTemplates/members_AllTestCases.ump @@ -6,8 +6,25 @@ class UmpleTToPhpUnit { members_AllTestCases <><<# +boolean skipTest = false; +boolean isConcrete = false; 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() >>() { <<# @@ -66,5 +83,8 @@ for (TestCase tc : model.getTestSuite(0).getTestcases()) } +skipTest = false; +} + #>>!>> } \ No newline at end of file diff --git a/UmpleTToRubyUnit/UmpleTLTemplates/members_AllTestCases.ump b/UmpleTToRubyUnit/UmpleTLTemplates/members_AllTestCases.ump index 9bc69baadc..7cfa5706d6 100644 --- a/UmpleTToRubyUnit/UmpleTLTemplates/members_AllTestCases.ump +++ b/UmpleTToRubyUnit/UmpleTLTemplates/members_AllTestCases.ump @@ -6,8 +6,27 @@ class UmpleTToRubyUnit { members_AllTestCases <><<# + +boolean skipTest = false; +boolean isConcrete = false; + 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 <<# for (int i = 0; i>!>> } \ No newline at end of file diff --git a/cruise.umple.test-parser/src/ump/TestCaseTemplate_model.ump b/cruise.umple.test-parser/src/ump/TestCaseTemplate_model.ump index 24c1159300..b149b81cc3 100644 --- a/cruise.umple.test-parser/src/ump/TestCaseTemplate_model.ump +++ b/cruise.umple.test-parser/src/ump/TestCaseTemplate_model.ump @@ -51,7 +51,9 @@ class TestCase { name; int locOrder; - + String concreteLanguage = ""; + boolean isTargeted = false; + boolean isConcrete = false; 0..1 testcase -- * TestInitialization inits; 0..1 testcase -- * Assertion assertions; diff --git a/cruise.umple.test-parser/src/ump/mbt_parser_src.ump b/cruise.umple.test-parser/src/ump/mbt_parser_src.ump index c2118644c4..a88adcd29d 100644 --- a/cruise.umple.test-parser/src/ump/mbt_parser_src.ump +++ b/cruise.umple.test-parser/src/ump/mbt_parser_src.ump @@ -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")) { //system.out.println("\tInitlocOrder"); diff --git a/cruise.umple.test-parser/src/ump/mbt_parsing.grammar b/cruise.umple.test-parser/src/ump/mbt_parsing.grammar index 44882a51b8..7e33ed1ad1 100644 --- a/cruise.umple.test-parser/src/ump/mbt_parsing.grammar +++ b/cruise.umple.test-parser/src/ump/mbt_parsing.grammar @@ -25,7 +25,7 @@ thenCont: (THEN:)? [[testCase]]* //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 ; //testinitAtt testInitAtt : [~identifier] [~attributeName] = [[pValue]] ; diff --git a/cruise.umple/src/UmpleInternalParser_CodeClass.ump b/cruise.umple/src/UmpleInternalParser_CodeClass.ump index 331b9c7b25..3f75c4afa6 100755 --- a/cruise.umple/src/UmpleInternalParser_CodeClass.ump +++ b/cruise.umple/src/UmpleInternalParser_CodeClass.ump @@ -320,6 +320,11 @@ class UmpleInternalParser analyzeClassTestCase(token,aClass); } + else if (token.is("genericTestCase")) + { + analyzeClassGenericTestCase(token,aClass); + } + else if (token.is("testSequence")) { analyzeClassTestSequence(token,aClass); diff --git a/cruise.umple/src/UmpleInternalParser_CodeTest.ump b/cruise.umple/src/UmpleInternalParser_CodeTest.ump index 45ee535b91..7676bcf78f 100755 --- a/cruise.umple/src/UmpleInternalParser_CodeTest.ump +++ b/cruise.umple/src/UmpleInternalParser_CodeTest.ump @@ -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]<>"; + String nonPascalRegex = "[=|(|!|\\s]<>"; + //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<> + String tempGroup = matcher.group(); + String tempReplacement = tempGroup.replace("<>", 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(<>) it is rather a parameter in this case or String tempAtt = <> + { + String tempGroup = nonMatcher.group(); + String tempReplacement = tempGroup.replace("<>", 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); + } + } + } + + diff --git a/cruise.umple/src/umple_classes.grammar b/cruise.umple/src/umple_classes.grammar index e745318ce5..8f9fea67ac 100644 --- a/cruise.umple/src/umple_classes.grammar +++ b/cruise.umple/src/umple_classes.grammar @@ -29,7 +29,7 @@ associationClassDefinition : associationClass [name] { [[associationClassContent enumerationDefinition : enum [name] { [enumValue](, [enumValue])* } // 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]] innerClass : [[innerStaticClass]] | [[innerNonStaticClass]] innerStaticClass : static [[classDefinition]] @@ -81,6 +81,9 @@ interfaceTest : test [~testName] ; testSequence : testSequence [~sequenceName] { [[testSequenceEntry]] } testSequenceEntry : [~name] ( -> [~name] )* ; +// Generic test case rules +genericTestCase : generic test [~testCaseName] OPEN_ROUND_BRACKET [~genericElement] CLOSE_ROUND_BRACKET { ( [**code] )* } + diff --git a/cruise.umple/test/cruise/umple/implementation/test/GenericTestCase.ump b/cruise.umple/test/cruise/umple/implementation/test/GenericTestCase.ump new file mode 100644 index 0000000000..8f62838065 --- /dev/null +++ b/cruise.umple/test/cruise/umple/implementation/test/GenericTestCase.ump @@ -0,0 +1,25 @@ + +class Person { + + id; + name; + address; + + + generic test checkifLogged(attribute){ + Person p1 ( "S1425", "John", "Ottawa") ; + String valueToCheck = p1.get<>(); + ps1.getValue(<>); + boolean isLogged = p1.checkIsLogged(valueToCheck); + assertTrue(logged == "true"); + } + + + + + + String returnSumOfValues (int x, int y) { return x+y;} + +} + + \ No newline at end of file diff --git a/cruise.umple/test/cruise/umple/implementation/test/TestTemplateTest.java b/cruise.umple/test/cruise/umple/implementation/test/TestTemplateTest.java index 02a342b782..f21decb3b1 100644 --- a/cruise.umple/test/cruise/umple/implementation/test/TestTemplateTest.java +++ b/cruise.umple/test/cruise/umple/implementation/test/TestTemplateTest.java @@ -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()); + + + } + diff --git a/cruise.umple/test/cruise/umple/implementation/test/testGenericTestcase.test.txt b/cruise.umple/test/cruise/umple/implementation/test/testGenericTestcase.test.txt new file mode 100644 index 0000000000..95c522a850 --- /dev/null +++ b/cruise.umple/test/cruise/umple/implementation/test/testGenericTestcase.test.txt @@ -0,0 +1,94 @@ +/*PLEASE DO NOT EDIT THIS CODE*/ +/*This code was generated using the UMPLE ${last.version} modeling language!*/ + + + +////---- Tests for GenericTestCase ----///// +Test Person { + //tests for :id + + test attribute_id { + + assertTrue( person.setId("RandomString1")); + assertTrue( person.getId() =="RandomString1"); + assertTrue( person.setId("RandomString2")); + assertTrue( person.getId()=="RandomString2"); + assertFalse( person.getId() =="RandomString1"); + + } + + //tests for :name + + test attribute_name { + + assertTrue( person.setName("RandomString1")); + assertTrue( person.getName() =="RandomString1"); + assertTrue( person.setName("RandomString2")); + assertTrue( person.getName()=="RandomString2"); + assertFalse( person.getName() =="RandomString1"); + + } + + //tests for :address + + test attribute_address { + + assertTrue( person.setAddress("RandomString1")); + assertTrue( person.getAddress() =="RandomString1"); + assertTrue( person.setAddress("RandomString2")); + assertTrue( person.getAddress()=="RandomString2"); + assertFalse( person.getAddress() =="RandomString1"); + + } + + + //------------------ + //User-defined Tests + //------------------ + + + test checkifLogged_id { + Person p1 ( "S1425", "John", "Ottawa") ; + String valueToCheck = p1.getId(); + ps1.getValue(id); + boolean isLogged = p1.checkIsLogged(valueToCheck); + assertTrue(logged == "true"); + } + + + + + + + + test checkifLogged_name { + Person p1 ( "S1425", "John", "Ottawa") ; + String valueToCheck = p1.getName(); + ps1.getValue(name); + boolean isLogged = p1.checkIsLogged(valueToCheck); + assertTrue(logged == "true"); + } + + + + + + + + test checkifLogged_address { + Person p1 ( "S1425", "John", "Ottawa") ; + String valueToCheck = p1.getAddress(); + ps1.getValue(address); + boolean isLogged = p1.checkIsLogged(valueToCheck); + assertTrue(logged == "true"); + } + + + + + + + + + +} \ No newline at end of file