SlideShare a Scribd company logo
1 of 44
Test-Driven Development
           of
      Xtext DSLs
        Moritz Eysholdt
we strive for...

...product quality   ...development speed


        features         fast

robustness                      agile

     correctness
without tests   with tests


add source code         easy          easy


 modify source
                        risky          safe
    code

application state
                        large         small
while debugging
without tests           with tests


add source code         easy                    easy


 modify source
                        risky                    safe
    code

application state
                        large                   small
                                          lots of redundancy
while debugging                         architecture may erode
                                    maintenance increasingly difficult
without tests           with tests


add source code         easy                    easy
                                    extracting small test + debugging
                                           may be faster then
 modify source                          debugging large scenario
                        risky                    safe
    code

application state
                        large                   small
while debugging
qualities of (unit) tests

                        fast   run them locally
                    specific    avoid redundancy
          efficient to write    save time
       efficient to maintain    expectations can change
  easy to read/understand      involve domain experts
self-explanatory on failure!   save time
JUnit 4
XtextRunner

         ParameterizedXtextRunner
Test...
  content assist                     validation rules
                         scoping
 quickfixes
               value conversion formatter
  parser/AST                              serializer
                       derived values
exported EObjects
                                    semantic highlighting
               typesystem
 autoedit
                   code generator       interpreter
Test...
  content assist                    validation rules
                         scoping
 quickfixes
              value conversion formatter
            your own code
  parser/AST                         serializer
            integration with framework
            the framework values
                     derived
exported EObjects
                               semantic highlighting
               typesystem
 autoedit
                   code generator     interpreter
person Peter
person Frank knows Peter
person Peter
person Frank knows Peter




                           Model:
                           	   persons+=Person*;
                           	
                           Person:
                           	   'person' name=ID
                           	   ('knows' knows=[Person|ID])?;
test scoping

person Peter
person Frank knows Peter




                           Model:
                           	   persons+=Person*;
                           	
                           Person:
                           	   'person' name=ID
                           	   ('knows' knows=[Person|ID])?;
StringBuilder modelString = new StringBuilder();
modelString.append("person Petern");
modelString.append("person Frank knows Petern");
Model model = parseHelper.parse(modelString);
StringBuilder modelString = new StringBuilder();
modelString.append("person Petern");
modelString.append("person Frank knows Petern");
Model model = parseHelper.parse(modelString);

Person peter = model.getPersons().get(0);
EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

IScope scope = scopeProvider.getScope(peter, reference);
StringBuilder modelString = new StringBuilder();
modelString.append("person Petern");
modelString.append("person Frank knows Petern");
Model model = parseHelper.parse(modelString);

Person peter = model.getPersons().get(0);
EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

IScope scope = scopeProvider.getScope(peter, reference);

List<String> actualList = Lists.newArrayList();
for (IEObjectDescription desc : scope.getAllElements())
  actualList.add(desc.getName().toString());
String actual = Joiner.on(", ").join(actualList);

Assert.assertEquals("Peter, Frank", actual);
@RunWith(XtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;

    @Inject private IScopeProvider scopeProvider;

    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
      modelString.append("person Frank knows Petern");
      Model model = parseHelper.parse(modelString);

        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);
    }
}
@RunWith(XtextRunner.class)
                                                                     JUnit 4 Runner
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;

    @Inject private IScopeProvider scopeProvider;

    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
      modelString.append("person Frank knows Petern");
      Model model = parseHelper.parse(modelString);

        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);
    }
}
@RunWith(XtextRunner.class)
                                                                      JUnit 4 Runner
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;
                                                                   Google Guice Injector
    @Inject private IScopeProvider scopeProvider;
                                                                     Injected Instances
    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
      modelString.append("person Frank knows Petern");
      Model model = parseHelper.parse(modelString);

        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);
    }
}
@RunWith(XtextRunner.class)
                                                                      JUnit 4 Runner
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;
                                                                   Google Guice Injector
    @Inject private IScopeProvider scopeProvider;
                                                                     Injected Instances
    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
      modelString.append("person Frank knows Petern");            Backups and Restores
      Model model = parseHelper.parse(modelString);
                                                                      EMF Registries
        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);
    }
}
@RunWith(XtextRunner.class)
                                                                       JUnit 4 Runner
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;
                                                                   Google Guice Injector
    @Inject private IScopeProvider scopeProvider;
                                                                     Injected Instances
    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
      modelString.append("person Frank knows Petern");            Backups and Restores
      Model model = parseHelper.parse(modelString);
                                                                      EMF Registries
        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);      Plain JUnit Test:
                                                                              No OSGi
        List<String> actualList = Lists.newArrayList();
                                                                    Injector via StandaloneSetup
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);
    }
}
@RunWith(XtextRunner.class)
                                                                       JUnit 4 Runner
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;
                                                                   Google Guice Injector
    @Inject private IScopeProvider scopeProvider;
                                                                     Injected Instances
    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
      modelString.append("person Frank knows Petern");            Backups and Restores
      Model model = parseHelper.parse(modelString);
                                                                      EMF Registries
        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);
                                                         FAST!
                                                                      Plain JUnit Test:
                                                                              No OSGi
        List<String> actualList = Lists.newArrayList();
                                                                    Injector via StandaloneSetup
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);
    }
}
@RunWith(XtextRunner.class)
                                                                       JUnit 4 Runner
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;
                                                                   Google Guice Injector
    @Inject private IScopeProvider scopeProvider;
                                                                     Injected Instances
    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
      modelString.append("person Frank knows Petern");            Backups and Restores
      Model model = parseHelper.parse(modelString);
                                                                      EMF Registries
        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);
                                                         FAST!
                                                                      Plain JUnit Test:
                                                                              No OSGi
        List<String> actualList = Lists.newArrayList();
                                                                    Injector via StandaloneSetup
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);                 Plug-In JUnit Test:
    }                                                              Eclipse Headless or Workbench
}
                                                                         Injector via Activator
@RunWith(XtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;

    @Inject private IScopeProvider scopeProvider;

    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
      modelString.append("person Frank knows Petern");
      Model model = parseHelper.parse(modelString);

        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);
    }
}
@RunWith(XtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;

    @Inject private IScopeProvider scopeProvider;

    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
            Exchange Components: Customize InjectorProvider
      modelString.append("person Frank knows Petern");
      Model model = parseHelper.parse(modelString); via
                          Components are configured        Google Guice
        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);
    }
}
@RunWith(XtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;

    @Inject private IScopeProvider scopeProvider;

    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
            Exchange Components: Customize InjectorProvider
      modelString.append("person Frank knows Petern");
      Model model = parseHelper.parse(modelString); via
                          Components are configured         Google Guice
        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
                Mocking Components vs. Reusing Components
        String actual = Joiner.on(", ").join(actualList);

               Integration tests don’t hurt when they’re
        Assert.assertEquals("Peter, Frank", actual);  not fragile, but specific and fast
    }     Reusing Parser+Linker is more convenient than creating models programmatically
}
@RunWith(XtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;

    @Inject private IScopeProvider scopeProvider;

    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
      modelString.append("person Frank knows Petern");
      Model model = parseHelper.parse(modelString);
              (XtextRunner)
        Person Java Example
               peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);
    }
}
@RunWith(XtextRunner.class)
                      @RunWith(typeof(XtextRunner))
@InjectWith(TestDemoInjectorProvider.class)
                      @InjectWith(typeof(TestDemoInjectorProvider))
public class ScopingTestPlain {
                      class ScopingTestXtend {

    @Inject private ParseHelper<Model> parseHelper;
                          @Inject extension ParseHelper<Model>
                          @Inject extension IScopeProvider
    @Inject private IScopeProvider scopeProvider;
                          @Test
    @Test public void testScope1() throws Exception {
                          def testScope1() {
      StringBuilder modelString model = '''
                          	 val = new StringBuilder();
      modelString.append("person Petern");
                          		    person Peter
      modelString.append("person Frank Frank knows Peter
                          		    person knows Petern");
      Model model = parseHelper.parse(modelString);
                          	 '''.parse
              (XtextRunner)
        Person Java Example
               peter = model.getPersons().get(0);
                              val scope = getScope(model.persons.head, eINSTANCE.person_Knows)
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();
                              val actual = scope.allElements.map[name.toString].join(", ")
        IScope scope = scopeProvider.getScope(peter, reference);
                              assertEquals("Peter, Frank", actual);
        List<String> actualList = Lists.newArrayList();
                            }
        for (IEObjectDescription desc : scope.getAllElements())
                          }
          actualList.add(desc.getName().toString());
        String actual = Joiner.on(", ").join(actualList);

        Assert.assertEquals("Peter, Frank", actual);
    }
}
@RunWith(XtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;
                                                                              Data Flow
    @Inject private IScopeProvider scopeProvider;

    @Test public void testScope1() throws Exception {
      StringBuilder modelString = new StringBuilder();
      modelString.append("person Petern");
      modelString.append("person Frank knows Petern");
      Model model = parseHelper.parse(modelString);                            prepare
        Person peter = model.getPersons().get(0);
        EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows();

        IScope scope = scopeProvider.getScope(peter, reference);

        List<String> actualList = Lists.newArrayList();                        process
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());

        String actual = Joiner.on(", ").join(actualList);
        Assert.assertEquals("Peter, Frank", actual);                          compare
    }
}
@RunWith(XtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
public class ScopingTestPlain {

    @Inject private ParseHelper<Model> parseHelper;
                                                                   Data Flow
    @Inject private IScopeProvider scopeProvider;

    @Test public void testScope1() throws Exception {




                         (DSL File)                                 prepare

        IScope scope = scopeProvider.getScope(peter, reference);

        List<String> actualList = Lists.newArrayList();             process
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());


                         (DSL File)                                compare
    }
}
person Peter
                                                            DSL-File
// XPECT elementsInScope at P|eter --> Frank, Peter, Jack
person Frank knows Peter

/* XPECT elementsInScope at P|eter ---
	   Frank, !Jim
--- */
person Jack knows Peter
person Peter
                                                                                 DSL-File
// XPECT elementsInScope at P|eter --> Frank, Peter, Jack
person Frank knows Peter

/* XPECT elementsInScope at P|eter ---
	   Frank, !Jim
--- */
person Jack knows Peter


@RunWith(ParameterizedXtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)                                  JUnit 4 Test
@ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo")
public class ScopingTestPlain {

    @InjectParameter private Offset offset;
    @Inject private IScopeProvider scopeProvider;
                                                                                   beta
    @ParameterSyntax("('at' offset=OFFSET)?")
    @XpectCommaSeparatedValues
    public Iterable<String> elementsInScope() throws Exception {
      Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent();

        IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond());

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        return actualList;
    }
}
person Peter

// XPECT elementsInScope at P|eter --> Frank, Peter, Jack
person Frank knows Peter

/* XPECT elementsInScope at P|eter ---
	   Frank, !Jim
--- */
person Jack knows Peter


@RunWith(ParameterizedXtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
@ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo")
public class ScopingTestPlain {

    @InjectParameter private Offset offset;
    @Inject private IScopeProvider scopeProvider;

    @ParameterSyntax("('at' offset=OFFSET)?")
    @XpectCommaSeparatedValues
    public Iterable<String> elementsInScope() throws Exception {
      Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent();

        IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond());

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        return actualList;
    }
}
person Peter

// XPECT elementsInScope at P|eter --> Frank, Peter, Jack
person Frank knows Peter

/* XPECT elementsInScope at P|eter ---
	   Frank, !Jim
--- */
person Jack knows Peter


@RunWith(ParameterizedXtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
                                                                     JUnit 4 Runner
@ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo")
public class ScopingTestPlain {

    @InjectParameter private Offset offset;
    @Inject private IScopeProvider scopeProvider;

    @ParameterSyntax("('at' offset=OFFSET)?")
    @XpectCommaSeparatedValues
    public Iterable<String> elementsInScope() throws Exception {
      Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent();

        IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond());

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        return actualList;
    }
}
person Peter

// XPECT elementsInScope at P|eter --> Frank, Peter, Jack
person Frank knows Peter

/* XPECT elementsInScope at P|eter ---
	   Frank, !Jim
--- */
person Jack knows Peter


@RunWith(ParameterizedXtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
                                                                     JUnit 4 Runner
@ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo")
public class ScopingTestPlain {

    @InjectParameter private Offset offset;
    @Inject private IScopeProvider scopeProvider;

    @ParameterSyntax("('at' offset=OFFSET)?")                     Folder with DSL-Files
    @XpectCommaSeparatedValues
    public Iterable<String> elementsInScope() throws Exception {
      Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent();

        IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond());

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        return actualList;
    }
}
person Peter

// XPECT elementsInScope at P|eter --> Frank, Peter, Jack
person Frank knows Peter

/* XPECT elementsInScope at P|eter ---                            Tests as Comments
	   Frank, !Jim
--- */
person Jack knows Peter


@RunWith(ParameterizedXtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
                                                                     JUnit 4 Runner
@ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo")
public class ScopingTestPlain {

    @InjectParameter private Offset offset;
    @Inject private IScopeProvider scopeProvider;

    @ParameterSyntax("('at' offset=OFFSET)?")                     Folder with DSL-Files
    @XpectCommaSeparatedValues
    public Iterable<String> elementsInScope() throws Exception {
      Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent();

        IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond());

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        return actualList;
    }
}
person Peter

// XPECT elementsInScope at P|eter --> Frank, Peter, Jack
person Frank knows Peter

/* XPECT elementsInScope at P|eter ---
	   Frank, !Jim                                                         Parameters
--- */                                                              STRING, ID, INT, OFFSET
person Jack knows Peter


@RunWith(ParameterizedXtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
@ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo")
public class ScopingTestPlain {

    @InjectParameter private Offset offset;                       Parameter Value
    @Inject private IScopeProvider scopeProvider;

    @ParameterSyntax("('at' offset=OFFSET)?")                     Parameter Syntax
    @XpectCommaSeparatedValues
    public Iterable<String> elementsInScope() throws Exception {
      Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent();

        IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond());

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        return actualList;
    }
}
person Peter

// XPECT elementsInScope at P|eter --> Frank, Peter, Jack
person Frank knows Peter

/* XPECT elementsInScope at P|eter ---
	   Frank, !Jim                                                         Parameters
--- */                                                              STRING, ID, INT, OFFSET
person Jack knows Peter


@RunWith(ParameterizedXtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
@ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo")
public class ScopingTestPlain {

    @InjectParameter private Offset offset;                       Parameter Value
    @Inject private IScopeProvider scopeProvider;

    @ParameterSyntax("('at' offset=OFFSET)?")                     Parameter Syntax
    @XpectCommaSeparatedValues
    public Iterable<String> elementsInScope() throws Exception {
      Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent();

        IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond());

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        return actualList;                                          Implicit/Explicit
    }
}                                                                     Parameters
person Peter

// XPECT elementsInScope at P|eter --> Frank, Peter, Jack
person Frank knows Peter

/* XPECT elementsInScope at P|eter ---
	   Frank, !Jim                                                         Expectation
--- */                                                                 SingleLine/MultiLine
person Jack knows Peter


@RunWith(ParameterizedXtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
@ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo")
public class ScopingTestPlain {

    @InjectParameter private Offset offset;
    @Inject private IScopeProvider scopeProvider;
                                                                  Expectation Kind
                                                                  @Xpect, @XpectString,
    @ParameterSyntax("('at' offset=OFFSET)?")                        @XpectLines
    @XpectCommaSeparatedValues
    public Iterable<String> elementsInScope() throws Exception {
      Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent();

        IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond());

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());
        return actualList;
    }
}
                     Actual Value
person Peter

// XPECT elementsInScope at P|eter --> Frank, Peter, Jack
person Frank knows Peter

/* XPECT elementsInScope at P|eter ---
	   Frank, !Jim                                                         Expectation
--- */                                                                 SingleLine/MultiLine
person Jack knows Peter


@RunWith(ParameterizedXtextRunner.class)
@InjectWith(TestDemoInjectorProvider.class)
@ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo")
public class ScopingTestPlain {

    @InjectParameter private Offset offset;
    @Inject private IScopeProvider scopeProvider;
                                                                  Expectation Kind
                                                                  @Xpect, @XpectString,
    @ParameterSyntax("('at' offset=OFFSET)?")                        @XpectLines
    @XpectCommaSeparatedValues
    public Iterable<String> elementsInScope() throws Exception {
      Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent();

        IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond());

        List<String> actualList = Lists.newArrayList();
        for (IEObjectDescription desc : scope.getAllElements())
          actualList.add(desc.getName().toString());                     CaseSensitive?
        return actualList;                                             WhitespaceSensitive?
    }                                                                       Ordered?
}
                     Actual Value
double click here
qualities - a retrospective

                        fast   (depends on developer)



                    specific    (depends on developer)



          efficient to write
       efficient to maintain
  easy to read/understand
self-explanatory on failure!
Eclipse DemoCamp November 2011
 07.11.2011, 18:15 – 22:00 Uhr, Bonn
 08.11.2011, 18:30 – 22:00 Uhr, Dresden
 28.11.2011, 18:30 – 22:00 Uhr, Berlin


Eclipse based DSL Tooling - Meet the Experts
 29.11.2011, 13:30 - 19:00 Uhr, Frankfurt a.M.
Xcore: ECore meets Xtext (Ed Merks)
Verteilte Modellierung mit CDO (Eike Stepper)
Ein Jahr Xtext im Einsatz für HMI-Definition (Stefan Weise & Gerd Zanker)


Embedded Software Engineering-Kongress
 06.12.2011 - 08.12.2011, 09:00 – 18:00 Uhr, Sindelfingen

More Related Content

What's hot

Entity framework code first
Entity framework code firstEntity framework code first
Entity framework code first
Confiz
 

What's hot (20)

Entity framework code first
Entity framework code firstEntity framework code first
Entity framework code first
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
 
Introduction to ASP.NET Core
Introduction to ASP.NET CoreIntroduction to ASP.NET Core
Introduction to ASP.NET Core
 
Extending the Xbase Typesystem
Extending the Xbase TypesystemExtending the Xbase Typesystem
Extending the Xbase Typesystem
 
5 collection framework
5 collection framework5 collection framework
5 collection framework
 
NestJS
NestJSNestJS
NestJS
 
TypeScript Best Practices
TypeScript Best PracticesTypeScript Best Practices
TypeScript Best Practices
 
The New JavaScript: ES6
The New JavaScript: ES6The New JavaScript: ES6
The New JavaScript: ES6
 
Typescript Fundamentals
Typescript FundamentalsTypescript Fundamentals
Typescript Fundamentals
 
React js programming concept
React js programming conceptReact js programming concept
React js programming concept
 
Javascript Design Patterns
Javascript Design PatternsJavascript Design Patterns
Javascript Design Patterns
 
Solid NodeJS with TypeScript, Jest & NestJS
Solid NodeJS with TypeScript, Jest & NestJSSolid NodeJS with TypeScript, Jest & NestJS
Solid NodeJS with TypeScript, Jest & NestJS
 
TypeScript Overview
TypeScript OverviewTypeScript Overview
TypeScript Overview
 
Express js
Express jsExpress js
Express js
 
Fundamental JavaScript [UTC, March 2014]
Fundamental JavaScript [UTC, March 2014]Fundamental JavaScript [UTC, March 2014]
Fundamental JavaScript [UTC, March 2014]
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express
 
Introduction to Node js
Introduction to Node jsIntroduction to Node js
Introduction to Node js
 
Entity Framework Core
Entity Framework CoreEntity Framework Core
Entity Framework Core
 
Asp.net state management
Asp.net state managementAsp.net state management
Asp.net state management
 
Angular
AngularAngular
Angular
 

Similar to Test-Driven Development of Xtext DSLs

Refactoring In Tdd The Missing Part
Refactoring In Tdd The Missing PartRefactoring In Tdd The Missing Part
Refactoring In Tdd The Missing Part
Gabriele Lana
 
Attacks against Microsoft network web clients
Attacks against Microsoft network web clients Attacks against Microsoft network web clients
Attacks against Microsoft network web clients
Positive Hack Days
 
Дмитрий Контрерас «Back to the future: the evolution of the Java Type System»
Дмитрий Контрерас «Back to the future: the evolution of the Java Type System»Дмитрий Контрерас «Back to the future: the evolution of the Java Type System»
Дмитрий Контрерас «Back to the future: the evolution of the Java Type System»
Anna Shymchenko
 

Similar to Test-Driven Development of Xtext DSLs (20)

Refactoring In Tdd The Missing Part
Refactoring In Tdd The Missing PartRefactoring In Tdd The Missing Part
Refactoring In Tdd The Missing Part
 
15 tips to improve your unit tests (Droidcon Berlin 2016 Barcamp)
15 tips to improve your unit tests (Droidcon Berlin 2016 Barcamp)15 tips to improve your unit tests (Droidcon Berlin 2016 Barcamp)
15 tips to improve your unit tests (Droidcon Berlin 2016 Barcamp)
 
Tdd & unit test
Tdd & unit testTdd & unit test
Tdd & unit test
 
Test driven development - JUnit basics and best practices
Test driven development - JUnit basics and best practicesTest driven development - JUnit basics and best practices
Test driven development - JUnit basics and best practices
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?
 
Atlassian Groovy Plugins
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy Plugins
 
Using xUnit as a Swiss-Aarmy Testing Toolkit
Using xUnit as a Swiss-Aarmy Testing ToolkitUsing xUnit as a Swiss-Aarmy Testing Toolkit
Using xUnit as a Swiss-Aarmy Testing Toolkit
 
Testing And Drupal
Testing And DrupalTesting And Drupal
Testing And Drupal
 
Better Code through Lint and Checkstyle
Better Code through Lint and CheckstyleBetter Code through Lint and Checkstyle
Better Code through Lint and Checkstyle
 
Static analysis: Around Java in 60 minutes
Static analysis: Around Java in 60 minutesStatic analysis: Around Java in 60 minutes
Static analysis: Around Java in 60 minutes
 
Spock: Test Well and Prosper
Spock: Test Well and ProsperSpock: Test Well and Prosper
Spock: Test Well and Prosper
 
Attacks against Microsoft network web clients
Attacks against Microsoft network web clients Attacks against Microsoft network web clients
Attacks against Microsoft network web clients
 
Дмитрий Контрерас «Back to the future: the evolution of the Java Type System»
Дмитрий Контрерас «Back to the future: the evolution of the Java Type System»Дмитрий Контрерас «Back to the future: the evolution of the Java Type System»
Дмитрий Контрерас «Back to the future: the evolution of the Java Type System»
 
Building a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to Space
 
Advances in Unit Testing: Theory and Practice
Advances in Unit Testing: Theory and PracticeAdvances in Unit Testing: Theory and Practice
Advances in Unit Testing: Theory and Practice
 
Junit_.pptx
Junit_.pptxJunit_.pptx
Junit_.pptx
 
Rc2010 tdd
Rc2010 tddRc2010 tdd
Rc2010 tdd
 
Full Text Search In PostgreSQL
Full Text Search In PostgreSQLFull Text Search In PostgreSQL
Full Text Search In PostgreSQL
 
C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607
 

More from meysholdt (6)

Serializing EMF models with Xtext
Serializing EMF models with XtextSerializing EMF models with Xtext
Serializing EMF models with Xtext
 
Turning Ideas Into Code Faster
Turning Ideas Into Code FasterTurning Ideas Into Code Faster
Turning Ideas Into Code Faster
 
Executable specifications for xtext
Executable specifications for xtextExecutable specifications for xtext
Executable specifications for xtext
 
Xbase - Implementing Domain-Specific Languages for Java
Xbase - Implementing Domain-Specific Languages for JavaXbase - Implementing Domain-Specific Languages for Java
Xbase - Implementing Domain-Specific Languages for Java
 
Codegeneration Goodies
Codegeneration GoodiesCodegeneration Goodies
Codegeneration Goodies
 
Converging Textual and Graphical Editors
Converging Textual  and Graphical EditorsConverging Textual  and Graphical Editors
Converging Textual and Graphical Editors
 

Recently uploaded

Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Peter Udo Diehl
 
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdfBreaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
UK Journal
 

Recently uploaded (20)

Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
 
Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024
 
What's New in Teams Calling, Meetings and Devices April 2024
What's New in Teams Calling, Meetings and Devices April 2024What's New in Teams Calling, Meetings and Devices April 2024
What's New in Teams Calling, Meetings and Devices April 2024
 
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
 
A Business-Centric Approach to Design System Strategy
A Business-Centric Approach to Design System StrategyA Business-Centric Approach to Design System Strategy
A Business-Centric Approach to Design System Strategy
 
Microsoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - QuestionnaireMicrosoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - Questionnaire
 
How we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdfHow we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdf
 
Free and Effective: Making Flows Publicly Accessible, Yumi Ibrahimzade
Free and Effective: Making Flows Publicly Accessible, Yumi IbrahimzadeFree and Effective: Making Flows Publicly Accessible, Yumi Ibrahimzade
Free and Effective: Making Flows Publicly Accessible, Yumi Ibrahimzade
 
WSO2CONMay2024OpenSourceConferenceDebrief.pptx
WSO2CONMay2024OpenSourceConferenceDebrief.pptxWSO2CONMay2024OpenSourceConferenceDebrief.pptx
WSO2CONMay2024OpenSourceConferenceDebrief.pptx
 
Enterprise Knowledge Graphs - Data Summit 2024
Enterprise Knowledge Graphs - Data Summit 2024Enterprise Knowledge Graphs - Data Summit 2024
Enterprise Knowledge Graphs - Data Summit 2024
 
Syngulon - Selection technology May 2024.pdf
Syngulon - Selection technology May 2024.pdfSyngulon - Selection technology May 2024.pdf
Syngulon - Selection technology May 2024.pdf
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM Performance
 
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdfBreaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
 
Intro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджераIntro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджера
 
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
 
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
 
Designing for Hardware Accessibility at Comcast
Designing for Hardware Accessibility at ComcastDesigning for Hardware Accessibility at Comcast
Designing for Hardware Accessibility at Comcast
 
AI revolution and Salesforce, Jiří Karpíšek
AI revolution and Salesforce, Jiří KarpíšekAI revolution and Salesforce, Jiří Karpíšek
AI revolution and Salesforce, Jiří Karpíšek
 
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfThe Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
 
Speed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in MinutesSpeed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in Minutes
 

Test-Driven Development of Xtext DSLs

  • 1. Test-Driven Development of Xtext DSLs Moritz Eysholdt
  • 2. we strive for... ...product quality ...development speed features fast robustness agile correctness
  • 3. without tests with tests add source code easy easy modify source risky safe code application state large small while debugging
  • 4. without tests with tests add source code easy easy modify source risky safe code application state large small lots of redundancy while debugging architecture may erode maintenance increasingly difficult
  • 5. without tests with tests add source code easy easy extracting small test + debugging may be faster then modify source debugging large scenario risky safe code application state large small while debugging
  • 6. qualities of (unit) tests fast run them locally specific avoid redundancy efficient to write save time efficient to maintain expectations can change easy to read/understand involve domain experts self-explanatory on failure! save time
  • 7. JUnit 4 XtextRunner ParameterizedXtextRunner
  • 8. Test... content assist validation rules scoping quickfixes value conversion formatter parser/AST serializer derived values exported EObjects semantic highlighting typesystem autoedit code generator interpreter
  • 9. Test... content assist validation rules scoping quickfixes value conversion formatter your own code parser/AST serializer integration with framework the framework values derived exported EObjects semantic highlighting typesystem autoedit code generator interpreter
  • 11. person Peter person Frank knows Peter Model: persons+=Person*; Person: 'person' name=ID ('knows' knows=[Person|ID])?;
  • 12. test scoping person Peter person Frank knows Peter Model: persons+=Person*; Person: 'person' name=ID ('knows' knows=[Person|ID])?;
  • 13. StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString);
  • 14. StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString); Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference);
  • 15. StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString); Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual);
  • 16. @RunWith(XtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; @Inject private IScopeProvider scopeProvider; @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString); Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); } }
  • 17. @RunWith(XtextRunner.class) JUnit 4 Runner @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; @Inject private IScopeProvider scopeProvider; @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString); Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); } }
  • 18. @RunWith(XtextRunner.class) JUnit 4 Runner @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; Google Guice Injector @Inject private IScopeProvider scopeProvider; Injected Instances @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString); Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); } }
  • 19. @RunWith(XtextRunner.class) JUnit 4 Runner @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; Google Guice Injector @Inject private IScopeProvider scopeProvider; Injected Instances @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Backups and Restores Model model = parseHelper.parse(modelString); EMF Registries Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); } }
  • 20. @RunWith(XtextRunner.class) JUnit 4 Runner @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; Google Guice Injector @Inject private IScopeProvider scopeProvider; Injected Instances @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Backups and Restores Model model = parseHelper.parse(modelString); EMF Registries Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); Plain JUnit Test: No OSGi List<String> actualList = Lists.newArrayList(); Injector via StandaloneSetup for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); } }
  • 21. @RunWith(XtextRunner.class) JUnit 4 Runner @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; Google Guice Injector @Inject private IScopeProvider scopeProvider; Injected Instances @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Backups and Restores Model model = parseHelper.parse(modelString); EMF Registries Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); FAST! Plain JUnit Test: No OSGi List<String> actualList = Lists.newArrayList(); Injector via StandaloneSetup for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); } }
  • 22. @RunWith(XtextRunner.class) JUnit 4 Runner @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; Google Guice Injector @Inject private IScopeProvider scopeProvider; Injected Instances @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Backups and Restores Model model = parseHelper.parse(modelString); EMF Registries Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); FAST! Plain JUnit Test: No OSGi List<String> actualList = Lists.newArrayList(); Injector via StandaloneSetup for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); Plug-In JUnit Test: } Eclipse Headless or Workbench } Injector via Activator
  • 23. @RunWith(XtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; @Inject private IScopeProvider scopeProvider; @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString); Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); } }
  • 24. @RunWith(XtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; @Inject private IScopeProvider scopeProvider; @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); Exchange Components: Customize InjectorProvider modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString); via Components are configured Google Guice Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); } }
  • 25. @RunWith(XtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; @Inject private IScopeProvider scopeProvider; @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); Exchange Components: Customize InjectorProvider modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString); via Components are configured Google Guice Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); Mocking Components vs. Reusing Components String actual = Joiner.on(", ").join(actualList); Integration tests don’t hurt when they’re Assert.assertEquals("Peter, Frank", actual); not fragile, but specific and fast } Reusing Parser+Linker is more convenient than creating models programmatically }
  • 26. @RunWith(XtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; @Inject private IScopeProvider scopeProvider; @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString); (XtextRunner) Person Java Example peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); } }
  • 27. @RunWith(XtextRunner.class) @RunWith(typeof(XtextRunner)) @InjectWith(TestDemoInjectorProvider.class) @InjectWith(typeof(TestDemoInjectorProvider)) public class ScopingTestPlain { class ScopingTestXtend { @Inject private ParseHelper<Model> parseHelper; @Inject extension ParseHelper<Model> @Inject extension IScopeProvider @Inject private IScopeProvider scopeProvider; @Test @Test public void testScope1() throws Exception { def testScope1() { StringBuilder modelString model = ''' val = new StringBuilder(); modelString.append("person Petern"); person Peter modelString.append("person Frank Frank knows Peter person knows Petern"); Model model = parseHelper.parse(modelString); '''.parse (XtextRunner) Person Java Example peter = model.getPersons().get(0); val scope = getScope(model.persons.head, eINSTANCE.person_Knows) EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); val actual = scope.allElements.map[name.toString].join(", ") IScope scope = scopeProvider.getScope(peter, reference); assertEquals("Peter, Frank", actual); List<String> actualList = Lists.newArrayList(); } for (IEObjectDescription desc : scope.getAllElements()) } actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); } }
  • 28. @RunWith(XtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; Data Flow @Inject private IScopeProvider scopeProvider; @Test public void testScope1() throws Exception { StringBuilder modelString = new StringBuilder(); modelString.append("person Petern"); modelString.append("person Frank knows Petern"); Model model = parseHelper.parse(modelString); prepare Person peter = model.getPersons().get(0); EReference reference = TestDemoPackage.eINSTANCE.getPerson_Knows(); IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); process for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); String actual = Joiner.on(", ").join(actualList); Assert.assertEquals("Peter, Frank", actual); compare } }
  • 29. @RunWith(XtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) public class ScopingTestPlain { @Inject private ParseHelper<Model> parseHelper; Data Flow @Inject private IScopeProvider scopeProvider; @Test public void testScope1() throws Exception { (DSL File) prepare IScope scope = scopeProvider.getScope(peter, reference); List<String> actualList = Lists.newArrayList(); process for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); (DSL File) compare } }
  • 30. person Peter DSL-File // XPECT elementsInScope at P|eter --> Frank, Peter, Jack person Frank knows Peter /* XPECT elementsInScope at P|eter --- Frank, !Jim --- */ person Jack knows Peter
  • 31. person Peter DSL-File // XPECT elementsInScope at P|eter --> Frank, Peter, Jack person Frank knows Peter /* XPECT elementsInScope at P|eter --- Frank, !Jim --- */ person Jack knows Peter @RunWith(ParameterizedXtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) JUnit 4 Test @ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo") public class ScopingTestPlain { @InjectParameter private Offset offset; @Inject private IScopeProvider scopeProvider; beta @ParameterSyntax("('at' offset=OFFSET)?") @XpectCommaSeparatedValues public Iterable<String> elementsInScope() throws Exception { Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent(); IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond()); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); return actualList; } }
  • 32. person Peter // XPECT elementsInScope at P|eter --> Frank, Peter, Jack person Frank knows Peter /* XPECT elementsInScope at P|eter --- Frank, !Jim --- */ person Jack knows Peter @RunWith(ParameterizedXtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) @ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo") public class ScopingTestPlain { @InjectParameter private Offset offset; @Inject private IScopeProvider scopeProvider; @ParameterSyntax("('at' offset=OFFSET)?") @XpectCommaSeparatedValues public Iterable<String> elementsInScope() throws Exception { Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent(); IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond()); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); return actualList; } }
  • 33. person Peter // XPECT elementsInScope at P|eter --> Frank, Peter, Jack person Frank knows Peter /* XPECT elementsInScope at P|eter --- Frank, !Jim --- */ person Jack knows Peter @RunWith(ParameterizedXtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) JUnit 4 Runner @ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo") public class ScopingTestPlain { @InjectParameter private Offset offset; @Inject private IScopeProvider scopeProvider; @ParameterSyntax("('at' offset=OFFSET)?") @XpectCommaSeparatedValues public Iterable<String> elementsInScope() throws Exception { Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent(); IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond()); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); return actualList; } }
  • 34. person Peter // XPECT elementsInScope at P|eter --> Frank, Peter, Jack person Frank knows Peter /* XPECT elementsInScope at P|eter --- Frank, !Jim --- */ person Jack knows Peter @RunWith(ParameterizedXtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) JUnit 4 Runner @ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo") public class ScopingTestPlain { @InjectParameter private Offset offset; @Inject private IScopeProvider scopeProvider; @ParameterSyntax("('at' offset=OFFSET)?") Folder with DSL-Files @XpectCommaSeparatedValues public Iterable<String> elementsInScope() throws Exception { Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent(); IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond()); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); return actualList; } }
  • 35. person Peter // XPECT elementsInScope at P|eter --> Frank, Peter, Jack person Frank knows Peter /* XPECT elementsInScope at P|eter --- Tests as Comments Frank, !Jim --- */ person Jack knows Peter @RunWith(ParameterizedXtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) JUnit 4 Runner @ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo") public class ScopingTestPlain { @InjectParameter private Offset offset; @Inject private IScopeProvider scopeProvider; @ParameterSyntax("('at' offset=OFFSET)?") Folder with DSL-Files @XpectCommaSeparatedValues public Iterable<String> elementsInScope() throws Exception { Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent(); IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond()); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); return actualList; } }
  • 36. person Peter // XPECT elementsInScope at P|eter --> Frank, Peter, Jack person Frank knows Peter /* XPECT elementsInScope at P|eter --- Frank, !Jim Parameters --- */ STRING, ID, INT, OFFSET person Jack knows Peter @RunWith(ParameterizedXtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) @ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo") public class ScopingTestPlain { @InjectParameter private Offset offset; Parameter Value @Inject private IScopeProvider scopeProvider; @ParameterSyntax("('at' offset=OFFSET)?") Parameter Syntax @XpectCommaSeparatedValues public Iterable<String> elementsInScope() throws Exception { Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent(); IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond()); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); return actualList; } }
  • 37. person Peter // XPECT elementsInScope at P|eter --> Frank, Peter, Jack person Frank knows Peter /* XPECT elementsInScope at P|eter --- Frank, !Jim Parameters --- */ STRING, ID, INT, OFFSET person Jack knows Peter @RunWith(ParameterizedXtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) @ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo") public class ScopingTestPlain { @InjectParameter private Offset offset; Parameter Value @Inject private IScopeProvider scopeProvider; @ParameterSyntax("('at' offset=OFFSET)?") Parameter Syntax @XpectCommaSeparatedValues public Iterable<String> elementsInScope() throws Exception { Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent(); IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond()); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); return actualList; Implicit/Explicit } } Parameters
  • 38. person Peter // XPECT elementsInScope at P|eter --> Frank, Peter, Jack person Frank knows Peter /* XPECT elementsInScope at P|eter --- Frank, !Jim Expectation --- */ SingleLine/MultiLine person Jack knows Peter @RunWith(ParameterizedXtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) @ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo") public class ScopingTestPlain { @InjectParameter private Offset offset; @Inject private IScopeProvider scopeProvider; Expectation Kind @Xpect, @XpectString, @ParameterSyntax("('at' offset=OFFSET)?") @XpectLines @XpectCommaSeparatedValues public Iterable<String> elementsInScope() throws Exception { Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent(); IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond()); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); return actualList; } } Actual Value
  • 39. person Peter // XPECT elementsInScope at P|eter --> Frank, Peter, Jack person Frank knows Peter /* XPECT elementsInScope at P|eter --- Frank, !Jim Expectation --- */ SingleLine/MultiLine person Jack knows Peter @RunWith(ParameterizedXtextRunner.class) @InjectWith(TestDemoInjectorProvider.class) @ResourceURIs(baseDir = "testdata/", fileExtensions = "testdemo") public class ScopingTestPlain { @InjectParameter private Offset offset; @Inject private IScopeProvider scopeProvider; Expectation Kind @Xpect, @XpectString, @ParameterSyntax("('at' offset=OFFSET)?") @XpectLines @XpectCommaSeparatedValues public Iterable<String> elementsInScope() throws Exception { Pair<EObject, EStructuralFeature> pair = offset.getEStructuralFeatureByParent(); IScope scope = scopeProvider.getScope(pair.getFirst(), (EReference) pair.getSecond()); List<String> actualList = Lists.newArrayList(); for (IEObjectDescription desc : scope.getAllElements()) actualList.add(desc.getName().toString()); CaseSensitive? return actualList; WhitespaceSensitive? } Ordered? } Actual Value
  • 40.
  • 41.
  • 43. qualities - a retrospective fast (depends on developer) specific (depends on developer) efficient to write efficient to maintain easy to read/understand self-explanatory on failure!
  • 44. Eclipse DemoCamp November 2011 07.11.2011, 18:15 – 22:00 Uhr, Bonn 08.11.2011, 18:30 – 22:00 Uhr, Dresden 28.11.2011, 18:30 – 22:00 Uhr, Berlin Eclipse based DSL Tooling - Meet the Experts 29.11.2011, 13:30 - 19:00 Uhr, Frankfurt a.M. Xcore: ECore meets Xtext (Ed Merks) Verteilte Modellierung mit CDO (Eike Stepper) Ein Jahr Xtext im Einsatz für HMI-Definition (Stefan Weise & Gerd Zanker) Embedded Software Engineering-Kongress 06.12.2011 - 08.12.2011, 09:00 – 18:00 Uhr, Sindelfingen

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n