DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. A simple way to test Eclipse-based editors

A simple way to test Eclipse-based editors

Alex Ruiz user avatar by
Alex Ruiz
·
Oct. 20, 11 · Interview
Like (0)
Save
Tweet
Share
7.70K Views

Join the DZone community and get the full member experience.

Join For Free

After two releases of the open source version of protobuf-dt and ten Google-internal ones, code complexity grow to a point that more comprehensive testing is needed. Even though the practices in this post can be used to test different aspects of an Eclipse editor, we’ll focus on testing scoping.

Verifying that scoping works correctly involves:

  1. Specifying and parsing protocol buffer-content to use for testing
  2. Find a specific element in the parsed file
  3. Verify that scoping returns all the possible elements that can match the element found in step #2

An additional requirement is to make tests as lightweight as possible (e.g. do not require to instantiate a full Eclipse for running tests.)

1. Specifying and parsing protocol buffer-contents to use

My first attempt was to put all the protocol buffer code in a StringBuilder and then passed it to my XtextRule to get an AST back, as follows:

@Rule public XtextRule xtext = createWith(integrationTestSetup());
 
@Test public void should_provide_Property_fields_for_custom_field_option() {
  StringBuilder proto = new StringBuilder();
  proto.append("package com.google.proto;                   ")
       .append("import 'google/protobuf/descriptor.proto';  ")
       .append("                                            ")
       .append("extend google.protobuf.FieldOptions {       ")
       .append("  optional int32 code = 1000;               ")
       .append("  optional int32 info = 1001;               ")
       .append("}                                           ")
       .append("                                            ")
       .append("message Person {                            ") 
       .append("  optional boolean active = 1 [(code) = 68];")
       .append("}                                           ");
  Protobuf root = xtext.parseText(proto);
  // test implementation
}

Needless to say, writing and maintaining this is a real PITA. To make it readable I have to add extra whitespace to each line so the whole thing looks square. In addition, copy/paste code from the protocol buffer editor requires also adding append and quotes to each line, plus formatting. On top of that, it makes the test method too long.

An alternative approach was to have .proto files in the file system. I was not happy with this approach since anybody reading the code will need to go to two places to understand what the test is doing.

Finally, I found a better approach: specify the protocol buffer text as a comment!

I didn’t come up with this idea myself, I’m just borrowing it from CDT. After implementing a simpler, but similar approach, my test looks like this:

// package com.google.proto;
// import 'google/protobuf/descriptor.proto';
//  
// extend google.protobuf.FieldOptions {
//   optional int32 code = 1000;
//   optional int32 info = 1001;
// }
//  
// message Person {
//   optional boolean active = 1 [(code) = 68];
// }
@Test public void should_provide_Property_fields_for_custom_field_option() {
  Protobuf root = xtext.root();
  // test implementation
}

This is a big improvement! First of all, the test method ends up being shorter and easier to read. Second, it is easy to type something in the protocol buffer editor, copy it, and paste it above a test method. Then I just have to highlight it and press Ctrl+/ to have the text converted to a comment.

In this new scenario, my custom XtextRule does the following,:

  1. extracts the comment of each test method and creates a method name > comment mapping
  2. parses the comment of a test method and creates an AST just before executing the test method, not earlier
  3. keeps a reference to the root node of the AST, to be used by the test method itself

It looks good, but what about imported .proto files?

When testing scoping, it is absolutely necessary to verify that imported types are included correctly.

I originally had .proto files to be imported in the file system and stored in Git, which is ugly for the reason I mentioned before.

To make things better, I borrowed another idea from CDT: specify the text and file name of the .proto file to be imported in comments, XtextRule will create the file in the file system just before executing a test method.

Here is an example:

// // Create file custom-options.proto
// 
// package com.google.proto;
//
// import "google/protobuf/descriptor.proto";
//
// extend google.protobuf.FileOptions {
//   optional int32 code = 1000;
//   optional int32 info = 1002;
// }  
 
// package com.google.proto;
//  
// import 'custom-options.proto';
//
// option (code) = 68;
@Test public void should_provide_imported_Property_fields_for_custom_option() {
  // test implementation
}

In the example above we have two comments for a test method. The first one tells my XtextRule to create a file named “custom-options.proto” before executing the test method. The second comment will be the one parsed and whose AST will be stored by the XtextRule (just like in the previous example.)

Neat, isn’t it? :)

2. Find a specific element in the parsed file

This step is necessary to ensure that scoping returns all the possible types that a given reference may be pointing to.

In this example:

// package com.google.proto;
// import 'google/protobuf/descriptor.proto';
//  
// extend google.protobuf.FieldOptions {
//   optional int32 code = 1000;
//   optional int32 info = 1001;
// }
//  
// message Person {
//   optional boolean active = 1 [(info) = 68];
// }
@Test public void should_provide_Property_fields_for_custom_field_option() {
}

my test is going to verify that scoping returns the field options code and info as potential matches for (code). To do so, I first need to find the proper AST element that (code) represents.

Let’s say I want to search for the custom field option info. My original approach would require the following:

  1. Find all the elements in the AST of type CustomFieldOption
  2. If any result is returned from #1, find the one whose name is “info”

Here is an example:

Protobuf root = xtext.root();
// statically imported from CustomFieldOptionFinder
CustomFieldOption option = findCustomFieldOption(name("info"), in(root));

This solution by itself is not too bad, and it works! Unfortunately it requires one specialized finder per type in the AST. For a relatively simple language like Protocol Buffers, it would require more than 10 finders, which is too much code to maintain just for testing.

Enter CDT with a better approach, which requires only one finder for all the types in the AST. This finder looks for elements this way:

  1. Find the first element matching some text
  2. Verify that the found element is of the the specified type and has the specified name

For example:

CustomFieldOption option = xtext.find("info", ")", CustomFieldOption.class);

To find the custom option “info” this finder will:

  1. concatenates the Strings passed as arguments and find the first element that matches the text “info)”
  2. verify that the found element is a CustomFieldOption and has name “info” (the first String argument only)

As you can see, this approach is the complete opposite of my original one.

Since only one finder is needed, I can have my XtextRule create it and pass the root of the AST to it. This way, I don’t have to pass it to the finder every time I perform a lookup.

3. Verifying that scoping returns the correct types

This is actually DSL-specific. My only recommendation here is, if you are using JUnit, write your own Hamcrest matchers to keep test code short and readable, and without duplication.

Putting it all together

Here is how one of my tests for protobuf-dt looks like:

// message Person {
//   optional Type type = 1 [ctype = STRING];
// }
@Test public void should_provide_Property_fields_for_native_field_option() {
  // We have an overloaded version of "find" that takes only one <code>String</code>, 
  // to be used when the text to find and the name to match are the same.
  NativeFieldOption option = xtext.find("ctype", NativeFieldOption.class);
  IScope scope = provider.scope_PropertyRef_property(option.getProperty(), reference);
  Collection<Property> fieldOptions = descriptor().optionsOfType(FIELD);
  assertThat(descriptionsIn(scope), containAll(fieldOptions));
}

Please feel free to click these links to find the code of:

  • XtextRule
  • ModelFinder
  • or just get the project’s source code, as described here

Feedback is always welcome! :)

Future posts

There are a couple of useful things I have done with Xtext that I’d like to blog about in the near future:

  • Adding spell checking to comments and strings
  • Opening files outside an Eclipse workspace
  • Making Xtext work with file names, instead of file extensions

Now it is a matter of finding the time and energy!

 

From http://alexruiz.developerblogs.com/?p=1962

Testing File system code style Test method Element

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • 5 Steps for Getting Started in Deep Learning
  • Best CI/CD Tools for DevOps: A Review of the Top 10
  • Unlocking the Power of Elasticsearch: A Comprehensive Guide to Complex Search Use Cases
  • Getting a Private SSL Certificate Free of Cost

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: