In progress [Issue 125] Support for custom options.

Adding more tests. Code cleanup.
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainAllProperties.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainAllProperties.java
new file mode 100644
index 0000000..1de1eea
--- /dev/null
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainAllProperties.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import com.google.eclipse.protobuf.protobuf.Property;
+
+import org.eclipse.emf.ecore.EObject;
+import org.hamcrest.*;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class ContainAllProperties extends BaseMatcher<IEObjectDescriptions> {
+
+  private final Collection<Property> properties = new ArrayList<Property>();
+
+  static ContainAllProperties containAll(Collection<Property> properties) {
+    return new ContainAllProperties(properties);
+  }
+  
+  private ContainAllProperties(Collection<Property> properties) {
+    this.properties.addAll(properties);
+  }
+  
+  public boolean matches(Object arg) {
+    if (!(arg instanceof IEObjectDescriptions)) return false;
+    IEObjectDescriptions descriptions = (IEObjectDescriptions) arg;
+    if (descriptions.size() != properties.size()) return false;
+    for (Property property : properties) {
+      String name = property.getName();
+      EObject described = descriptions.objectDescribedAs(name);
+      if (described != property) return false;
+    }
+    return true;
+  }
+
+  public void describeTo(Description description) {
+    List<String> names = new ArrayList<String>();
+    for (Property property : properties) {
+      names.add(property.getName());
+    }
+    description.appendValue(names);
+  }
+}
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainAllPropertiesInMessage.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainAllPropertiesInMessage.java
new file mode 100644
index 0000000..5a7f7b0
--- /dev/null
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainAllPropertiesInMessage.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static org.eclipse.xtext.EcoreUtil2.getAllContentsOfType;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+
+import com.google.eclipse.protobuf.protobuf.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class ContainAllPropertiesInMessage extends BaseMatcher<IEObjectDescriptions> {
+
+  private final Message message;
+
+  static ContainAllPropertiesInMessage containAllPropertiesIn(Message message) {
+    return new ContainAllPropertiesInMessage(message);
+  }
+  
+  private ContainAllPropertiesInMessage(Message message) {
+    this.message = message;
+  }
+  
+  public boolean matches(Object arg) {
+    if (!(arg instanceof IEObjectDescriptions)) return false;
+    IEObjectDescriptions descriptions = (IEObjectDescriptions) arg;
+    List<Property> properties = allProperties();
+    if (descriptions.size() != properties.size()) return false;
+    for (Property property : properties) {
+      String name = property.getName();
+      EObject described = descriptions.objectDescribedAs(name);
+      if (described != property) return false;
+    }
+    return true;
+  }
+
+  public void describeTo(Description description) {
+    List<String> names = new ArrayList<String>();
+    for (Property property : allProperties()) {
+      names.add(property.getName());
+    }
+    description.appendValue(names);
+  }
+
+  private List<Property> allProperties() {
+    return getAllContentsOfType(message, Property.class);
+  }
+}
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainNames.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainNames.java
new file mode 100644
index 0000000..39f3e8d
--- /dev/null
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainNames.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import org.hamcrest.*;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class ContainNames extends BaseMatcher<IEObjectDescriptions> {
+
+  private final String[] expectedNames;
+
+  static ContainNames containAll(String... names) {
+    return new ContainNames(names);
+  }
+  
+  private ContainNames(String... names) {
+    expectedNames = names;
+  }
+  
+  public boolean matches(Object arg) {
+    if (!(arg instanceof IEObjectDescriptions)) return false;
+    IEObjectDescriptions descriptions = (IEObjectDescriptions) arg;
+    List<String> names = new ArrayList<String>(descriptions.names());
+    if (names.size() != expectedNames.length) return false;
+    for (String name : expectedNames) {
+      boolean removed = names.remove(name);
+      if (!removed) return false;
+    }
+    return names.isEmpty();
+  }
+
+  public void describeTo(Description description) {
+    description.appendValue(Arrays.toString(expectedNames));
+  }
+}
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/IEObjectDescriptions.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/IEObjectDescriptions.java
index 4b4ab01..6dab125 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/IEObjectDescriptions.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/IEObjectDescriptions.java
@@ -8,6 +8,8 @@
  */
 package com.google.eclipse.protobuf.scoping;
 
+import static java.util.Collections.unmodifiableSet;
+
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.xtext.naming.QualifiedName;
 import org.eclipse.xtext.resource.IEObjectDescription;
@@ -21,13 +23,17 @@
 class IEObjectDescriptions {
 
   static IEObjectDescriptions descriptionsIn(IScope scope) {
-    return new IEObjectDescriptions(scope);
+    return descriptions(scope.getAllElements());
   }
 
+  static IEObjectDescriptions descriptions(Iterable<IEObjectDescription> elements) {
+    return new IEObjectDescriptions(elements);
+  }
+  
   private final Map<String, IEObjectDescription> descriptions = new LinkedHashMap<String, IEObjectDescription>();
   
-  private IEObjectDescriptions(IScope scope) {
-    for (IEObjectDescription d : scope.getAllElements()) {
+  private IEObjectDescriptions(Iterable<IEObjectDescription> elements) {
+    for (IEObjectDescription d : elements) {
       QualifiedName name = d.getName();
       descriptions.put(name.toString(), d);
     }
@@ -42,6 +48,10 @@
     return descriptions.size();
   }
   
+  Collection<String> names() {
+    return unmodifiableSet(descriptions.keySet()); 
+  }
+  
   @Override public String toString() {
     return descriptions.keySet().toString();
   }
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_LiteralRef_literal_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_LiteralRef_literal_Test.java
index a0bef42..33305db 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_LiteralRef_literal_Test.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_LiteralRef_literal_Test.java
@@ -100,6 +100,31 @@
     assertThat(descriptionsIn(scope), containAllLiteralsIn(typeEnum));
   }
 
+  @Test public void should_provide_Literals_for_property_of_custom_option() {
+    MultiLineTextBuilder proto = new MultiLineTextBuilder();
+    proto.append("import 'google/protobuf/descriptor.proto';")
+         .append("                                          ")
+         .append("enum Type {                               ")
+         .append("  ONE = 0;                                ")
+         .append("  TWO = 1;                                ")
+         .append("}                                         ")
+         .append("                                          ")
+         .append("message Info {                            ")
+         .append("  optional Type type = 1;                 ")
+         .append("}                                         ")
+         .append("                                          ")
+         .append("extend google.protobuf.FileOptions {      ")
+         .append("  optional Info info = 1000;              ")
+         .append("}                                         ")
+         .append("                                          ")
+         .append("option (info).type = ONE;                 ");
+    Protobuf root = xtext.parseText(proto);
+    Option option = findOption(name("info"), in(root));
+    IScope scope = provider.scope_LiteralRef_literal(valueOf(option), reference);
+    Enum typeEnum = findEnum(name("Type"), in(root));
+    assertThat(descriptionsIn(scope), containAllLiteralsIn(typeEnum));
+  }
+
   private static LiteralRef valueOf(Option option) {
     return (LiteralRef) option.getValue();
   }
@@ -118,7 +143,7 @@
   
   private ProtoDescriptor descriptor() {
     ProtoDescriptorProvider descriptorProvider = xtext.getInstanceOf(ProtoDescriptorProvider.class);
-    return descriptorProvider.descriptor("google/protobuf/descriptor.proto");
+    return descriptorProvider.primaryDescriptor();
   }
 
   @Test public void should_provide_Literals_for_custom_field_option() {
@@ -144,6 +169,33 @@
     assertThat(descriptionsIn(scope), containAllLiteralsIn(typeEnum));
   }
 
+  @Test public void should_provide_Literals_for_property_of_custom_field_option() {
+    MultiLineTextBuilder proto = new MultiLineTextBuilder();
+    proto.append("import 'google/protobuf/descriptor.proto';        ")
+         .append("                                                  ")
+         .append("enum Type {                                       ")
+         .append("  ONE = 0;                                        ")
+         .append("  TWO = 1;                                        ")
+         .append("}                                                 ")
+         .append("                                                  ")
+         .append("message Info {                                    ")
+         .append("  optional Type type = 1;                         ")
+         .append("}                                                 ")
+         .append("                                                  ")
+         .append("extend google.protobuf.FieldOptions {             ")
+         .append("  optional Info info = 1000;                      ")
+         .append("}                                                 ")
+         .append("                                                  ")
+         .append("message Person {                                  ")
+         .append("  optional boolean active = 1 [(info).type = ONE];")
+         .append("}                                                 ");
+    Protobuf root = xtext.parseText(proto);
+    FieldOption option = findFieldOption(name("info"), in(root));
+    IScope scope = provider.scope_LiteralRef_literal(valueOf(option), reference);
+    Enum typeEnum = findEnum(name("Type"), in(root));
+    assertThat(descriptionsIn(scope), containAllLiteralsIn(typeEnum));
+  }
+
   private static LiteralRef valueOf(FieldOption option) {
     return (LiteralRef) option.getValue();
   }
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_PropertyRef_property_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_PropertyRef_property_Test.java
new file mode 100644
index 0000000..8ab57b8
--- /dev/null
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_PropertyRef_property_Test.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static com.google.eclipse.protobuf.junit.model.find.ExtendMessageFinder.findExtendMessage;
+import static com.google.eclipse.protobuf.junit.model.find.FieldOptionFinder.*;
+import static com.google.eclipse.protobuf.junit.model.find.Name.name;
+import static com.google.eclipse.protobuf.junit.model.find.OptionFinder.findOption;
+import static com.google.eclipse.protobuf.junit.model.find.Root.in;
+import static com.google.eclipse.protobuf.model.OptionType.*;
+import static com.google.eclipse.protobuf.scoping.ContainAllProperties.containAll;
+import static com.google.eclipse.protobuf.scoping.ContainNames.containAll;
+import static com.google.eclipse.protobuf.scoping.IEObjectDescriptions.*;
+import static org.eclipse.xtext.EcoreUtil2.getAllContentsOfType;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.junit.util.MultiLineTextBuilder;
+import com.google.eclipse.protobuf.protobuf.*;
+
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.xtext.scoping.IScope;
+import org.junit.*;
+
+import java.util.*;
+
+/**
+ * Tests for <code>{@link ProtobufScopeProvider#scope_PropertyRef_property(PropertyRef, EReference)}</code>
+ * 
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ProtobufScopeProvider_scope_PropertyRef_property_Test {
+
+  private static EReference reference;
+  
+  @BeforeClass public static void setUpOnce() {
+    reference = mock(EReference.class);
+  }
+  
+  @Rule public XtextRule xtext = XtextRule.integrationTestSetup();
+  
+  private ProtobufScopeProvider provider;
+  
+  @Before public void setUp() {
+    provider = xtext.getInstanceOf(ProtobufScopeProvider.class);
+  }
+
+  @Test public void should_provide_Property_fields_for_native_option() {
+    Protobuf root = xtext.parseText("option optimize_for = SPEED;");
+    Option option = findOption(name("optimize_for"), in(root));
+    IScope scope = provider.scope_PropertyRef_property(option.getProperty(), reference);
+    Collection<Property> fileOptions = descriptor().optionsOfType(FILE);
+    assertThat(descriptionsIn(scope), containAll(fileOptions));
+  }
+  
+  @Test public void should_provide_Property_fields_for_native_field_option() {
+    MultiLineTextBuilder proto = new MultiLineTextBuilder();
+    proto.append("message Person {                          ")
+         .append("  optional Type type = 1 [ctype = STRING];")
+         .append("}                                         ");
+    Protobuf root = xtext.parseText(proto);
+    NativeFieldOption option = findNativeFieldOption(name("ctype"), in(root));
+    IScope scope = provider.scope_PropertyRef_property(option.getProperty(), reference);
+    Collection<Property> fieldOptions = descriptor().optionsOfType(FIELD);
+    assertThat(descriptionsIn(scope), containAll(fieldOptions));
+  }
+
+  private ProtoDescriptor descriptor() {
+    ProtoDescriptorProvider descriptorProvider = xtext.getInstanceOf(ProtoDescriptorProvider.class);
+    return descriptorProvider.primaryDescriptor();
+  }
+
+  @Test public void should_provide_Property_fields_for_custom_option() {
+    MultiLineTextBuilder proto = new MultiLineTextBuilder();
+    proto.append("package com.google.proto;                 ")
+         .append("import 'google/protobuf/descriptor.proto';")
+         .append("                                          ")
+         .append("extend google.protobuf.FileOptions {      ")
+         .append("  optional int32 code = 1000;             ")
+         .append("  optional string name = 1001;            ")
+         .append("}                                         ")
+         .append("                                          ")
+         .append("option (code) = 68;                       ");
+    Protobuf root = xtext.parseText(proto);
+    Option option = findOption(name("code"), in(root));
+    IScope scope = provider.scope_PropertyRef_property(option.getProperty(), reference);
+    ExtendMessage extendFileOptionsMessage = findExtendMessage(name("FileOptions"), in(root));
+    Map<String, Property> properties = propertiesOf(extendFileOptionsMessage);
+    Property code = properties.get("code");
+    assertThat(descriptions(scope.getElements(code)), containAll("code", "proto.code", "google.proto.code", 
+                                                                 "com.google.proto.code", ".com.google.proto.code"));
+    Property name = properties.get("name");
+    assertThat(descriptions(scope.getElements(name)), containAll("name", "proto.name", "google.proto.name", 
+                                                                 "com.google.proto.name", ".com.google.proto.name"));
+  }
+
+  @Test public void should_provide_Property_fields_for_custom_field_option() {
+    MultiLineTextBuilder proto = new MultiLineTextBuilder();
+    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 string name = 1001;              ")
+         .append("}                                           ")
+         .append("                                            ")
+         .append("message Person {                            ")
+         .append("  optional boolean active = 1 [(code) = 68];")
+         .append("}                                           ");
+    Protobuf root = xtext.parseText(proto);
+    CustomFieldOption option = findCustomFieldOption(name("code"), in(root));
+    IScope scope = provider.scope_PropertyRef_property(option.getProperty(), reference);
+    ExtendMessage extendFileOptionsMessage = findExtendMessage(name("FieldOptions"), in(root));
+    Map<String, Property> properties = propertiesOf(extendFileOptionsMessage);
+    Property code = properties.get("code");
+    assertThat(descriptions(scope.getElements(code)), containAll("code", "proto.code", "google.proto.code", 
+                                                                 "com.google.proto.code", ".com.google.proto.code"));
+    Property name = properties.get("name");
+    assertThat(descriptions(scope.getElements(name)), containAll("name", "proto.name", "google.proto.name", 
+                                                                 "com.google.proto.name", ".com.google.proto.name"));
+  }
+
+  private static Map<String, Property> propertiesOf(ExtendMessage m) {
+    Map<String, Property> properties = new HashMap<String, Property>();
+    for (Property p : getAllContentsOfType(m, Property.class)) {
+      properties.put(p.getName(), p);
+    }
+    return properties;
+  }
+}
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_SimplePropertyRef_property_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_SimplePropertyRef_property_Test.java
new file mode 100644
index 0000000..07142e6
--- /dev/null
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider_scope_SimplePropertyRef_property_Test.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static com.google.eclipse.protobuf.junit.model.find.FieldOptionFinder.findCustomFieldOption;
+import static com.google.eclipse.protobuf.junit.model.find.MessageFinder.findMessage;
+import static com.google.eclipse.protobuf.junit.model.find.Name.name;
+import static com.google.eclipse.protobuf.junit.model.find.OptionFinder.findCustomOption;
+import static com.google.eclipse.protobuf.junit.model.find.Root.in;
+import static com.google.eclipse.protobuf.scoping.ContainAllPropertiesInMessage.containAllPropertiesIn;
+import static com.google.eclipse.protobuf.scoping.IEObjectDescriptions.descriptionsIn;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.junit.util.MultiLineTextBuilder;
+import com.google.eclipse.protobuf.protobuf.*;
+
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.xtext.scoping.IScope;
+import org.junit.*;
+
+/**
+ * Tests for <code>{@link ProtobufScopeProvider#scope_SimplePropertyRef_property(SimplePropertyRef, EReference)}</code>
+ * 
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ProtobufScopeProvider_scope_SimplePropertyRef_property_Test {
+
+  private static EReference reference;
+  
+  @BeforeClass public static void setUpOnce() {
+    reference = mock(EReference.class);
+  }
+  
+  @Rule public XtextRule xtext = XtextRule.integrationTestSetup();
+  
+  private ProtobufScopeProvider provider;
+  
+  @Before public void setUp() {
+    provider = xtext.getInstanceOf(ProtobufScopeProvider.class);
+  }
+
+  @Test public void should_provide_Property_fields_for_custom_option_field() {
+    MultiLineTextBuilder proto = new MultiLineTextBuilder();
+    proto.append("import 'google/protobuf/descriptor.proto';")
+         .append("                                          ")
+         .append("message Type {                            ")
+         .append("  optional int32 code = 1;                ")
+         .append("  optional string name = 2;               ")
+         .append("}                                         ")
+         .append("                                          ")
+         .append("extend google.protobuf.FileOptions {      ")
+         .append("  optional Type type = 1000;              ")
+         .append("}                                         ")
+         .append("                                          ")
+         .append("option (type).code = 68;                  ");
+    Protobuf root = xtext.parseText(proto);
+    CustomOption option = findCustomOption(name("type"), in(root));
+    IScope scope = provider.scope_SimplePropertyRef_property(option.getPropertyField(), reference);
+    Message typeMessage = findMessage(name("Type"), in(root));
+    assertThat(descriptionsIn(scope), containAllPropertiesIn(typeMessage));
+  }
+
+  @Test public void should_provide_Property_fields_for_custom_field_option_field() {
+    MultiLineTextBuilder proto = new MultiLineTextBuilder();
+    proto.append("import 'google/protobuf/descriptor.proto';       ")
+         .append("                                                 ")
+         .append("message Type {                                   ")
+         .append("  optional int32 code = 1;                       ")
+         .append("  optional string name = 2;                      ")
+         .append("}                                                ")
+         .append("                                                 ")
+         .append("extend google.protobuf.FieldOptions {            ")
+         .append("  optional Type type = 1000;                     ")
+         .append("}                                                ")
+         .append("                                                 ")
+         .append("message Person {                                 ")
+         .append("  optional boolean active = 1 [(type).code = 68];")
+         .append("}                                                ");
+    Protobuf root = xtext.parseText(proto);
+    CustomFieldOption option = findCustomFieldOption(name("type"), in(root));
+    IScope scope = provider.scope_SimplePropertyRef_property(option.getPropertyField(), reference);
+    Message typeMessage = findMessage(name("Type"), in(root));
+    assertThat(descriptionsIn(scope), containAllPropertiesIn(typeMessage));
+  }
+}
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/XtextRule.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/XtextRule.java
index 8a49248..ff1a5de 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/XtextRule.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/XtextRule.java
@@ -37,8 +37,7 @@
  */
 public class XtextRule implements MethodRule {
 
-  private final ISetup setup;
-  private Injector injector;
+  private final Injector injector;
 
   public static XtextRule unitTestSetup() {
     return new XtextRule(new TestingStandaloneSetup());
@@ -49,11 +48,11 @@
   }
 
   private XtextRule(ISetup setup) {
-    this.setup = setup;
+    injector = setup.createInjectorAndDoEMFRegistration();
   }
 
   public Statement apply(Statement base, FrameworkMethod method, Object target) {
-    return new XtextStatement(base);
+    return base;
   }
 
   public Injector injector() {
@@ -100,21 +99,4 @@
   public <T> T getInstanceOf(Class<T> type) {
     return injector.getInstance(type);
   }
-
-  private class XtextStatement extends Statement {
-    private final Statement base;
-
-    public XtextStatement(Statement base) {
-      this.base = base;
-    }
-
-    @Override public void evaluate() throws Throwable {
-      setUpInjector();
-      base.evaluate();
-    }
-
-    private void setUpInjector() {
-      injector = setup.createInjectorAndDoEMFRegistration();
-    }
-  }
 }
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/model/find/FieldOptionFinder.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/model/find/FieldOptionFinder.java
index 252de82..6962e11 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/model/find/FieldOptionFinder.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/model/find/FieldOptionFinder.java
@@ -18,11 +18,23 @@
 public final class FieldOptionFinder {
 
   public static FieldOption findFieldOption(Name name, Root root) {
-    for (FieldOption option : getAllContentsOfType(root.value, FieldOption.class))
+    return fieldOption(name, root, FieldOption.class);
+  }
+  
+  public static NativeFieldOption findNativeFieldOption(Name name, Root root) {
+    return fieldOption(name, root, NativeFieldOption.class);
+  }
+
+  public static CustomFieldOption findCustomFieldOption(Name name, Root root) {
+    return fieldOption(name, root, CustomFieldOption.class);
+  }
+
+  private static <T extends FieldOption> T fieldOption(Name name, Root root, Class<T> optionType) {
+    for (T option : getAllContentsOfType(root.value, optionType))
       if (name.value.equals(nameOf(option))) return option;
     return null;
   }
-  
+
   private static String nameOf(FieldOption option) {
     if (option instanceof DefaultValueFieldOption) return "default";
     PropertyRef ref = null;
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/model/find/OptionFinder.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/model/find/OptionFinder.java
index 3cbe6f1..225b2ea 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/model/find/OptionFinder.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/model/find/OptionFinder.java
@@ -20,7 +20,15 @@
   private OptionFinder() {}
 
   public static Option findOption(Name name, Root root) {
-    for (Option option : getAllContentsOfType(root.value, Option.class))
+    return option(name, root, Option.class);
+  }
+
+  public static CustomOption findCustomOption(Name name, Root root) {
+    return option(name, root, CustomOption.class);
+  }
+
+  private static <T extends Option> T option(Name name, Root root, Class<T> optionType) {
+    for (T option : getAllContentsOfType(root.value, optionType))
       if (name.value.equals(nameOf(option))) return option;
     return null;
   }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java
index aa7f948..f95f1ef 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java
@@ -35,6 +35,7 @@
 
   private static final IHyperlink[] NO_HYPERLINKS = null;
 
+  // TODO support single quotes too.
   private static final char QUOTE = '\"';
 
   @Inject private EObjectAtOffsetHelper eObjectAtOffsetHelper;
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java
index 5cbffcc..7d9f1b7 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java
@@ -149,7 +149,8 @@
     return emptyList();
   }
 
-  private Collection<Property> optionsOfType(OptionType type) {
+  @VisibleForTesting
+  Collection<Property> optionsOfType(OptionType type) {
     return unmodifiableCollection(optionsByType.get(type).values());
   }