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/ContainsAllLiteralsInEnum.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainsAllLiteralsInEnum.java
new file mode 100644
index 0000000..ef76c93
--- /dev/null
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ContainsAllLiteralsInEnum.java
@@ -0,0 +1,64 @@
+/*
+ * 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.scoping.IEObjectDescriptions.descriptionsIn;
+import static org.eclipse.xtext.EcoreUtil2.getAllContentsOfType;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.scoping.IScope;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.eclipse.protobuf.protobuf.Enum;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class ContainsAllLiteralsInEnum extends BaseMatcher<IScope> {
+
+  private final Enum anEnum;
+
+  static ContainsAllLiteralsInEnum containsAllLiteralsIn(Enum anEnum) {
+    return new ContainsAllLiteralsInEnum(anEnum);
+  }
+  
+  private ContainsAllLiteralsInEnum(Enum anEnum) {
+    this.anEnum = anEnum;
+  }
+  
+  public boolean matches(Object arg) {
+    if (!(arg instanceof IScope)) return false;
+    IEObjectDescriptions descriptions = descriptionsIn((IScope) arg);
+    List<Literal> literals = allLiterals();
+    if (descriptions.size() != literals.size()) return false;
+    for (Literal literal : literals) {
+      String name = literal.getName();
+      EObject described = descriptions.objectDescribedAs(name);
+      if (described != literal) return false;
+    }
+    return true;
+  }
+
+  public void describeTo(Description description) {
+    List<String> names = new ArrayList<String>();
+    for (Literal literal : allLiterals()) {
+      names.add(literal.getName());
+    }
+    description.appendValue(names);
+  }
+
+  private List<Literal> allLiterals() {
+    return getAllContentsOfType(anEnum, Literal.class);
+  }
+}
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 db908a5..ec596d8 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
@@ -37,4 +37,8 @@
     IEObjectDescription d = descriptions.get(name);
     return d.getEObjectOrProxy();
   }
+  
+  int size() {
+    return descriptions.size();
+  }
 }
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/Descriptor_availableOptionsFor_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor_availableOptionsFor_Test.java
similarity index 98%
rename from com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/Descriptor_availableOptionsFor_Test.java
rename to com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor_availableOptionsFor_Test.java
index fdae084..afc525c 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/Descriptor_availableOptionsFor_Test.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor_availableOptionsFor_Test.java
@@ -27,7 +27,7 @@
  *
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class Descriptor_availableOptionsFor_Test {
+public class ProtoDescriptor_availableOptionsFor_Test {
 
   @Rule public XtextRule xtext = XtextRule.integrationTestSetup();
 
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 8017323..bab8572 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
@@ -8,24 +8,32 @@
  */
 package com.google.eclipse.protobuf.scoping;
 
+import static com.google.eclipse.protobuf.junit.model.find.EnumFinder.findEnum;
 import static com.google.eclipse.protobuf.junit.model.find.FieldOptionFinder.findFieldOption;
 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.scoping.IEObjectDescriptions.descriptionsIn;
-import static org.hamcrest.core.IsEqual.equalTo;
+import static com.google.eclipse.protobuf.scoping.ContainsAllLiteralsInEnum.containsAllLiteralsIn;
 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 org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.junit.util.MultiLineTextBuilder;
+import com.google.eclipse.protobuf.protobuf.Enum;
+import com.google.eclipse.protobuf.protobuf.FieldOption;
+import com.google.eclipse.protobuf.protobuf.LiteralRef;
+import com.google.eclipse.protobuf.protobuf.Option;
+import com.google.eclipse.protobuf.protobuf.Protobuf;
 
 /**
- * Tests for <code>{@link ProtobufScopeProvider#scope_LiteralRef_literal(LiteralRef, EReference)}</code>
+ * Tests for <code>{@link ProtobufScopeProvider#scope_LiteralRef_literal(LiteralRef, EReference)}</code>.
  * 
  * @author alruiz@google.com (Alex Ruiz)
  */
@@ -57,12 +65,85 @@
          .append("}                                        ");
     Protobuf root = xtext.parseText(proto);
     FieldOption option = findFieldOption(name("default"), in(root));
-    LiteralRef ref = (LiteralRef) option.getValue();
-    IScope scope = provider.scope_LiteralRef_literal(ref, reference);
-    IEObjectDescriptions descriptions = descriptionsIn(scope);
-    Literal one = (Literal) descriptions.objectDescribedAs("ONE");
-    assertThat(one.getName(), equalTo("ONE"));
-    Literal two = (Literal) descriptions.objectDescribedAs("TWO");
-    assertThat(two.getName(), equalTo("TWO"));
+    IScope scope = provider.scope_LiteralRef_literal(valueOf(option), reference);
+    Enum typeEnum = findEnum(name("Type"), in(root));
+    assertThat(scope, containsAllLiteralsIn(typeEnum));
+  }
+  
+  @Test public void should_provide_Literals_for_native_option() {
+    Protobuf root = xtext.parseText("option optimize_for = SPEED;");
+    Option option = findOption(name("optimize_for"), in(root));
+    IScope scope = provider.scope_LiteralRef_literal(valueOf(option), reference);
+    Enum optimizeModeEnum = descriptor().enumByName("OptimizeMode");
+    assertThat(scope, containsAllLiteralsIn(optimizeModeEnum));
+  }
+  
+  @Test public void should_provide_Literals_for_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("extend google.protobuf.FileOptions {      ")
+         .append("  optional Type type = 1000;              ")
+         .append("}                                         ")
+         .append("                                          ")
+         .append("option (type) = ONE;                      ");
+    Protobuf root = xtext.parseText(proto);
+    Option option = findOption(name("type"), in(root));
+    IScope scope = provider.scope_LiteralRef_literal(valueOf(option), reference);
+    Enum typeEnum = findEnum(name("Type"), in(root));
+    assertThat(scope, containsAllLiteralsIn(typeEnum));
+  }
+
+  private static LiteralRef valueOf(Option option) {
+    return (LiteralRef) option.getValue();
+  }
+  
+  @Test public void should_provide_Literals_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);
+    FieldOption option = findFieldOption(name("ctype"), in(root));
+    IScope scope = provider.scope_LiteralRef_literal(valueOf(option), reference);
+    Enum cTypeEnum = descriptor().enumByName("CType");
+    assertThat(scope, containsAllLiteralsIn(cTypeEnum));
+  }
+  
+  private ProtoDescriptor descriptor() {
+    ProtoDescriptorProvider descriptorProvider = xtext.getInstanceOf(ProtoDescriptorProvider.class);
+    return descriptorProvider.descriptor("google/protobuf/descriptor.proto");
+  }
+
+  @Test public void should_provide_Literals_for_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("extend google.protobuf.FieldOptions {        ")
+         .append("  optional Type type = 1000;                 ")
+         .append("}                                            ")
+         .append("                                             ")
+         .append("message Person {                             ")
+         .append("  optional boolean active = 1 [(type) = ONE];")
+         .append("}                                            ");
+    Protobuf root = xtext.parseText(proto);
+    FieldOption option = findFieldOption(name("type"), in(root));
+    IScope scope = provider.scope_LiteralRef_literal(valueOf(option), reference);
+    Enum typeEnum = findEnum(name("Type"), in(root));
+    assertThat(scope, containsAllLiteralsIn(typeEnum));
+  }
+
+  private static LiteralRef valueOf(FieldOption option) {
+    return (LiteralRef) option.getValue();
   }
 }
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 6f9b3c4..5cbffcc 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
@@ -165,9 +165,14 @@
     INode node = nodes.firstNodeForFeature(p, PROPERTY__TYPE);
     if (node == null) return null;
     String typeName = node.getText();
-    return (isEmpty(typeName)) ? null : enumsByName.get(typeName.trim());
+    return (isEmpty(typeName)) ? null : enumByName(typeName.trim());
   }
 
+  @VisibleForTesting
+  Enum enumByName(String name) {
+    return enumsByName.get(name);
+  }
+  
   /**
    * Returns all types in descriptor.proto.
    * @return all types in descriptor.proto.
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
index 35b9742..71c3955 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
@@ -90,12 +90,6 @@
     if (c instanceof Property) {
       anEnum = finder.enumTypeOf((Property) c);
     }
-    if (c instanceof NativeFieldOption) {
-      NativeFieldOption option = (NativeFieldOption) c;
-      ProtoDescriptor descriptor = descriptorProvider.primaryDescriptor();
-      Property p = fieldOptions.propertyFrom((NativeFieldOption) c);
-      anEnum = descriptor.enumTypeOf(p);
-    }
     return createScope(literalDescriptions.literalsOf(anEnum));
   }