Parameterize uri resolution and parsing of options, use package:path.

This helps make the compiler more configurable
to embed it in other systems (like pub transformers)

R=cbracken@google.com

Review URL: https://chromiumcodereview.appspot.com//269823003
diff --git a/.gitignore b/.gitignore
index 4a94bb0..ce6c509 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@
 .project
 .buildlog
 out
+*.sw?
diff --git a/Makefile b/Makefile
index f254dbb..fceb4f3 100644
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,8 @@
 						 lib/file_generator.dart \
 						 lib/indenting_writer.dart \
 						 lib/message_generator.dart \
+						 lib/options.dart \
+						 lib/output_config.dart \
 						 lib/protobuf_field.dart \
 						 lib/protoc.dart \
 						 lib/src/descriptor.pb.dart \
@@ -43,7 +45,7 @@
 $(PLUGIN_PATH): $(PLUGIN_SRC)
 	[ -d $(OUTPUT_DIR) ] || mkdir $(OUTPUT_DIR)
 	# --categories=all is a hack, it should be --categories=Server once dart2dart bug is fixed.
-	dart2js --checked --output-type=dart --package-root=packages --categories=all -o$(PLUGIN_PATH) bin/protoc_plugin.dart
+	dart2js --checked --output-type=dart --show-package-warnings --categories=all -o$(PLUGIN_PATH) bin/protoc_plugin.dart
 	dart prepend.dart $(PLUGIN_PATH)
 	chmod +x $(PLUGIN_PATH)
 
@@ -65,7 +67,7 @@
 build-test-protos: $(TEST_PROTO_LIBS)
 
 run-tests: build-test-protos
-	dart --checked --package-root=packages/ test/all_tests.dart
+	dart --checked test/all_tests.dart
 
 clean:
 	rm -rf $(OUTPUT_DIR)
diff --git a/bin/protoc_plugin.dart b/bin/protoc_plugin.dart
index b8c4d13..adb061b 100755
--- a/bin/protoc_plugin.dart
+++ b/bin/protoc_plugin.dart
@@ -4,7 +4,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:io';
-import 'package:protoc-plugin/protoc.dart';
+import 'package:protoc_plugin/protoc.dart';
 
 void main() {
   new CodeGenerator(stdin, stdout, stderr).generate();
diff --git a/lib/code_generator.dart b/lib/code_generator.dart
index 07dc931..986db0b 100644
--- a/lib/code_generator.dart
+++ b/lib/code_generator.dart
@@ -18,7 +18,14 @@
 
   CodeGenerator(this._streamIn, this._streamOut, this._streamErr);
 
-  void generate() {
+  /// Runs the code generator. The optional [optionParsers] can be used to
+  /// change how command line options are parsed (see [parseGenerationOptions]
+  /// for details), and [outputConfiguration] can be used to override where
+  /// generated files are created and how imports between generated files are
+  /// constructed (see [OutputConfiguration] for details).
+  void generate({
+      Map<String, SingleOptionParser> optionParsers,
+      OutputConfiguration outputConfiguration}) {
     _streamIn
         .fold(new BytesBuilder(), (builder, data) => builder..add(data))
         .then((builder) => builder.takeBytes())
@@ -27,13 +34,15 @@
             var response = new CodeGeneratorResponse();
 
             // Parse the options in the request. Return the errors is any.
-            var options = new GenerationOptions(request, response);
+            var options = parseGenerationOptions(
+                request, response, optionParsers);
             if (options == null) {
               _streamOut.add(response.writeToBuffer());
               return;
             }
 
-            var ctx = new GenerationContext(options);
+            var ctx = new GenerationContext(options, outputConfiguration == null
+                ? new DefaultOutputConfiguration() : outputConfiguration);
             List<FileGenerator> generators = <FileGenerator>[];
             for (FileDescriptorProto file in request.protoFile) {
               var generator = new FileGenerator(file, this, ctx);
@@ -52,59 +61,3 @@
   String get classname => null;
   String get fqname => '';
 }
-
-
-class GenerationOptions {
-  final Map<String, String> fieldNameOptions;
-
-  GenerationOptions._(this.fieldNameOptions);
-
-  // Parse the options in the request. If there was an error in the
-  // options null is returned and the error is set on the response.
-  factory GenerationOptions(request, response) {
-    var fieldNameOptions = <String, String>{};
-    var parameter = request.parameter != null ? request.parameter : '';
-    List<String> options = parameter.trim().split(',');
-    List<String> errors = [];
-    for (var option in options) {
-      option = option.trim();
-      if (option.isEmpty) continue;
-      List<String> nameValue = option.split('=');
-      if (nameValue.length != 1 && nameValue.length != 2) {
-        errors.add('Illegal option: $option');
-        continue;
-      }
-      String name = nameValue[0].trim();
-      String value;
-      if (nameValue.length > 1) value = nameValue[1].trim();
-      if (name == 'field_name') {
-        if (value == null) {
-          errors.add('Illegal option: $option');
-          continue;
-        }
-        List<String> fromTo = value.split('|');
-        if (fromTo.length != 2) {
-          errors.add('Illegal option: $option');
-          continue;
-        }
-        var fromName = fromTo[0].trim();
-        var toName = fromTo[1].trim();
-        if (fromName.length == 0 || toName.length == 0) {
-          errors.add('Illegal option: $option');
-          continue;
-        }
-        fieldNameOptions['.$fromName'] = toName;
-      } else {
-        errors.add('Illegal option: $option');
-      }
-    }
-    if (errors.length > 0) {
-      response.error = errors.join('\n');
-      return null;
-    } else {
-      return new GenerationOptions._(fieldNameOptions);
-    }
-  }
-
-  String fieldNameOption(String fqname) => fieldNameOptions[fqname];
-}
diff --git a/lib/file_generator.dart b/lib/file_generator.dart
index 982a813..35802d5 100644
--- a/lib/file_generator.dart
+++ b/lib/file_generator.dart
@@ -39,13 +39,6 @@
     return index == -1 ? fileName : fileName.substring(0, index);
   }
 
-  // Create the URI for the generated Dart file from the URI of the
-  // .proto file.
-  Uri _generatedFilePath(Uri protoFilePath) {
-    var dartFileName = _fileNameWithoutExtension(protoFilePath) + ".pb.dart";
-    return protoFilePath.resolve(dartFileName);
-  }
-
   String _generateClassName(Uri protoFilePath) {
     String s = _fileNameWithoutExtension(protoFilePath).replaceAll('-', '_');
     return '${s[0].toUpperCase()}${s.substring(1)}';
@@ -56,49 +49,15 @@
     return _fileNameWithoutExtension(protoFilePath).replaceAll('-', '_');
   }
 
-  Uri _relative(Uri target, Uri base) {
-    // Ignore the last segment of the base.
-    List<String> baseSegments =
-        base.pathSegments.sublist(0, base.pathSegments.length - 1);
-    List<String> targetSegments = target.pathSegments;
-    if (baseSegments.length == 1 && baseSegments[0] == '.') {
-      baseSegments = [];
-    }
-    if (targetSegments.length == 1 && targetSegments[0] == '.') {
-      targetSegments = [];
-    }
-    int common = 0;
-    int length = min(targetSegments.length, baseSegments.length);
-    while (common < length && targetSegments[common] == baseSegments[common]) {
-      common++;
-    }
-
-    final segments = <String>[];
-    if (common < baseSegments.length && baseSegments[common] == '..') {
-      throw new ArgumentError(
-          "Cannot create a relative path from $base to $target");
-    }
-    for (int i = common; i < baseSegments.length; i++) {
-      segments.add('..');
-    }
-    for (int i = common; i < targetSegments.length; i++) {
-      segments.add('${targetSegments[i]}');
-    }
-    if (segments.isEmpty) {
-      segments.add('.');
-    }
-    return new Uri(pathSegments: segments);
-  }
-
   CodeGeneratorResponse_File generateResponse() {
     MemoryWriter writer = new MemoryWriter();
     IndentingWriter out = new IndentingWriter('  ', writer);
 
     generate(out);
 
-    Uri filePath = new Uri(scheme: 'file', path: _fileDescriptor.name);
+    Uri filePath = new Uri.file(_fileDescriptor.name);
     return new CodeGeneratorResponse_File()
-        ..name = _generatedFilePath(filePath).path
+        ..name = _context.outputConfiguration.outputPathFor(filePath).path
         ..content = writer.toString();
   }
 
@@ -127,12 +86,13 @@
         // protoc should never generate an import with an absolute path.
         throw("FAILURE: Import with absolute path is not supported");
       }
-      // Create a relative path from the current file to the import.
-      Uri relativeProtoPath = _relative(importPath, filePath);
+      // Create a path from the current file to the imported proto.
+      Uri resolvedImport = _context.outputConfiguration.resolveImport(
+          importPath, filePath);
       // Find the file generator for this import as it contains the
       // package name.
       FileGenerator fileGenerator = _context.lookupFile(import);
-      out.print("import '${_generatedFilePath(relativeProtoPath)}'");
+      out.print("import '$resolvedImport'");
       if (package != fileGenerator.package && !fileGenerator.package.isEmpty) {
         out.print(' as ${fileGenerator.packageImportPrefix}');
       }
@@ -175,12 +135,13 @@
 
 class GenerationContext {
   final GenerationOptions options;
+  final OutputConfiguration outputConfiguration;
   final Map<String, ProtobufContainer> _registry =
       <String, ProtobufContainer>{};
   final Map<String, FileGenerator> _files =
       <String, FileGenerator>{};
 
-  GenerationContext(this.options);
+  GenerationContext(this.options, this.outputConfiguration);
 
   void register(ProtobufContainer container) {
     _registry[container.fqname] = container;
diff --git a/lib/options.dart b/lib/options.dart
new file mode 100644
index 0000000..c10d27d
--- /dev/null
+++ b/lib/options.dart
@@ -0,0 +1,117 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of protoc;
+
+/// Helper function implementing a generic option parser that reads
+/// `request.parameters` and treats each token as either a flag ("name") or a
+/// key-value pair ("name=value"). For each option "name", it looks up whether a
+/// [SingleOptionParser] exists in [parsers] and delegates the actual parsing of
+/// the option to it. Returns `true` if no errors were reported.
+bool genericOptionsParser(
+    CodeGeneratorRequest request, CodeGeneratorResponse response,
+    Map<String, SingleOptionParser> parsers) {
+  var parameter = request.parameter != null ? request.parameter : '';
+  var options = parameter.trim().split(',');
+  var map = <String, String>{};
+  var errors = [];
+
+  for (var option in options) {
+    option = option.trim();
+    if (option.isEmpty) continue;
+    var reportError = (details) {
+      errors.add('Error found trying to parse the option: $option.\n$details');
+    };
+
+    var nameValue = option.split('=');
+    if (nameValue.length != 1 && nameValue.length != 2) {
+      reportError('Options should be a single token, or a name=value pair');
+      continue;
+    }
+    var name = nameValue[0].trim();
+    var parser = parsers[name];
+    if (parser == null) {
+      reportError('Unknown option ($name).');
+      continue;
+    }
+
+    var value = nameValue.length > 1 ? nameValue[1].trim() : null;
+    parser.parse(name, value, reportError);
+  }
+
+  if (errors.length == 0) return true;
+
+  response.error = errors.join('\n');
+  return false;
+}
+
+/// Options expected by the protoc code generation compiler.
+class GenerationOptions {
+  /// Maps a fully qualified field name, to the desired name we wish to
+  /// generate. For example `MyMessage.has_field` to `HasFld`.
+  final Map<String, String> fieldNameOverrides;
+
+  GenerationOptions(this.fieldNameOverrides);
+}
+
+/// A parser for a name-value pair option. Options parsed in
+/// [genericOptionsParser] delegate to instances of this class to
+/// parse the value of a specific option.
+abstract class SingleOptionParser {
+
+  /// Parse the [name]=[value] value pair and report any errors to [onError]. If
+  /// the option is a flag, [value] will be null. Note, [name] is commonly
+  /// unused. It is provided because [SingleOptionParser] can be registered for
+  /// multiple option names in [genericOptionsParser].
+  void parse(String name, String value, onError(String details));
+}
+
+/// Parser used by the compiler, which supports the `field_name` option (see
+/// [FieldNameOptionParser]) and any additional option added in [parsers]. If
+/// [parsers] has a key for `field_name`, it will be ignored.
+GenerationOptions parseGenerationOptions(
+    CodeGeneratorRequest request, CodeGeneratorResponse response,
+    [Map<String, SingleOptionParser> parsers]) {
+  var fieldNameOptionParser = new FieldNameOptionParser();
+  var map = {};
+  if (parsers != null) parsers.forEach((k, v) { map[k] = v; });
+  map['field_name'] = fieldNameOptionParser;
+  if (genericOptionsParser(request, response, map)) {
+    return new GenerationOptions(fieldNameOptionParser.mappings);
+  }
+  return null;
+}
+
+/// A [SingleOptionParser] to parse the `field_name` option. This option
+/// overrides the default name given to some fields that would otherwise collide
+/// with existing field names in Dart core objects or in [GeneratedMessage].
+/// (see `README.md` for details).
+class FieldNameOptionParser implements SingleOptionParser {
+  /// Maps a fully qualified field name, to the desired name we wish to
+  /// generate. For example `MyMessage.has_field` to `HasFld`.
+  final Map<String, String> mappings = {};
+
+  void parse(String name, String value, onError(String message)) {
+    if (value == null) {
+      onError('Invalid field_name option, expected a non-emtpy value.');
+      return;
+    }
+
+    List<String> fromTo = value.split('|');
+    if (fromTo.length != 2) {
+      onError('Invalid field_name option, expected a single "|" separator.');
+      return;
+    }
+
+    var fromName = fromTo[0].trim();
+    var toName = fromTo[1].trim();
+    if (fromName.isEmpty || toName.isEmpty) {
+      onError('Invalid field_name option, '
+          '"from" and "to" names should not be empty.');
+      return;
+    }
+
+    mappings['.$fromName'] = toName;
+  }
+}
diff --git a/lib/output_config.dart b/lib/output_config.dart
new file mode 100644
index 0000000..9f76376
--- /dev/null
+++ b/lib/output_config.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of protoc;
+
+/// Configures where output of the protoc compiler should be placed and how to
+/// import one generated file from another.
+abstract class OutputConfiguration {
+
+  /// Returns [filePath] with it's extension replaced with '.pb.dart'.
+  String replacePathExtension(String filePath) =>
+      '${path.withoutExtension(filePath)}.pb.dart';
+
+  /// Returns [file] with it's extension replaced with '.pb.dart'.
+  Uri replaceUriExtension(Uri file) =>
+      path.url.toUri(replacePathExtension(path.url.fromUri(file)));
+
+  /// Resolves an import URI. Both [source] and [target] are .proto files,
+  /// where [target] is imported from [source]. The result URI can be used to
+  /// import [target]'s .pb.dart output from [source]'s .pb.dart output.
+  Uri resolveImport(Uri target, Uri source);
+
+  /// Returns the path, under the output folder, where the code will be
+  /// generated for [inputPath]. The input is expected to be a .proto file,
+  /// while the output is expected to be a .pb.dart file.
+  Uri outputPathFor(Uri inputPath);
+}
+
+/// Default [OutputConfiguration] that uses the same path as the input
+/// file for the output file (just replaces the extension), and that uses
+/// relative paths to resolve imports.
+class DefaultOutputConfiguration extends OutputConfiguration {
+
+  Uri outputPathFor(Uri input) => replaceUriExtension(input);
+
+  Uri resolveImport(Uri target, Uri source) {
+    var builder = path.url;
+    var targetPath = builder.fromUri(target);
+    var sourceDir = builder.dirname(builder.fromUri(source));
+    return builder.toUri(replacePathExtension(
+        builder.relative(targetPath, from: sourceDir)));
+  }
+}
diff --git a/lib/protobuf_field.dart b/lib/protobuf_field.dart
index 897de78..ca6d4d2 100644
--- a/lib/protobuf_field.dart
+++ b/lib/protobuf_field.dart
@@ -108,7 +108,7 @@
 
 
   factory ProtobufField(FieldDescriptorProto field,
-                        MessageGenerator parent,
+                        ProtobufContainer parent,
                         GenerationContext context) {
     bool required = field.label == FieldDescriptorProto_Label.LABEL_REQUIRED;
     bool repeats = field.label == FieldDescriptorProto_Label.LABEL_REPEATED;
@@ -372,8 +372,8 @@
       }
       return underscoresToCamelCase(name);
     }
-    var name = context.options.fieldNameOption(fqname);
-    return (name != null) ? name : underscoresToCamelCase(_field.name);
+    var name = context.options.fieldNameOverrides[fqname];
+    return name != null ? name : underscoresToCamelCase(_field.name);
   }
 
   int get wireType {
diff --git a/lib/protoc.dart b/lib/protoc.dart
index b745198..20c5dc7 100644
--- a/lib/protoc.dart
+++ b/lib/protoc.dart
@@ -2,9 +2,9 @@
 
 import 'dart:async';
 import 'dart:io';
-import 'dart:math';
 
 import 'package:protobuf/protobuf.dart';
+import 'package:path/path.dart' as path;
 
 import 'src/descriptor.pb.dart';
 import 'src/plugin.pb.dart';
@@ -16,5 +16,7 @@
 part 'file_generator.dart';
 part 'indenting_writer.dart';
 part 'message_generator.dart';
+part 'options.dart';
+part 'output_config.dart';
 part 'protobuf_field.dart';
 part 'writer.dart';
diff --git a/pubspec.yaml b/pubspec.yaml
index ef2c55b..0b2c917 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,12 +1,12 @@
-name: protoc-plugin
-version: 0.3.3
-authors:
-- Dart Team <misc@dartlang.org>
+name: protoc_plugin
+version: 0.3.4
+author: Dart Team <misc@dartlang.org>
 description: Protoc compiler plugin to generate Dart code
-homepage: https://github.com/dart-lang/protoc-plugin
+homepage: https://github.com/dart-lang/dart-protoc-plugin
 environment:
   sdk: '>=1.0.0 <2.0.0'
 dependencies:
-  protobuf: '>=0.3.3'
+  protobuf: '>=0.3.3 <0.4.0'
+  path: '>=1.0.0 <2.0.0'
 dev_dependencies:
-  unittest: '>=0.9.0 < 0.10.0'
+  unittest: '>=0.9.0 <0.11.0'
diff --git a/test/all_tests.dart b/test/all_tests.dart
index 627b2e3..6a1eefc 100755
--- a/test/all_tests.dart
+++ b/test/all_tests.dart
@@ -18,8 +18,10 @@
 import 'wire_format_test.dart' as wft;
 import 'reserved_names_test.dart' as rnt;
 import 'hash_code_test.dart' as hct;
+import 'package:unittest/compact_vm_config.dart';
 
 void main() {
+  useCompactVMConfiguration();
   egt.main();
   gmt.main();
   iwt.main();
diff --git a/test/enum_generator_test.dart b/test/enum_generator_test.dart
index 34a6c31..031e372 100755
--- a/test/enum_generator_test.dart
+++ b/test/enum_generator_test.dart
@@ -5,9 +5,9 @@
 
 library enum_generator_test;
 
-import 'package:protoc-plugin/src/descriptor.pb.dart';
-import 'package:protoc-plugin/src/plugin.pb.dart';
-import 'package:protoc-plugin/protoc.dart';
+import 'package:protoc_plugin/src/descriptor.pb.dart';
+import 'package:protoc_plugin/src/plugin.pb.dart';
+import 'package:protoc_plugin/protoc.dart';
 import 'package:unittest/unittest.dart';
 
 void main() {
@@ -50,12 +50,10 @@
                 ..number = 2]);
     MemoryWriter buffer = new MemoryWriter();
     IndentingWriter writer = new IndentingWriter('  ', buffer);
-    var options =
-        new GenerationOptions(
-            new CodeGeneratorRequest(), new CodeGeneratorResponse());
-    EnumGenerator eg =
-        new EnumGenerator(
-            ed, null, new GenerationContext(options));
+    var options = parseGenerationOptions(
+        new CodeGeneratorRequest(), new CodeGeneratorResponse());
+    EnumGenerator eg = new EnumGenerator(ed, null,
+        new GenerationContext(options, new DefaultOutputConfiguration()));
     eg.generate(writer);
     expect(buffer.toString(), expected);
   });
diff --git a/test/file_generator_test.dart b/test/file_generator_test.dart
index 8f0da3b..efaaa46 100644
--- a/test/file_generator_test.dart
+++ b/test/file_generator_test.dart
@@ -5,9 +5,9 @@
 
 library file_generator_test;
 
-import 'package:protoc-plugin/src/descriptor.pb.dart';
-import 'package:protoc-plugin/src/plugin.pb.dart';
-import 'package:protoc-plugin/protoc.dart';
+import 'package:protoc_plugin/src/descriptor.pb.dart';
+import 'package:protoc_plugin/src/plugin.pb.dart';
+import 'package:protoc_plugin/protoc.dart';
 import 'package:unittest/unittest.dart';
 
 
@@ -110,11 +110,10 @@
     FileDescriptorProto fd = buildFileDescriptor();
     MemoryWriter buffer = new MemoryWriter();
     IndentingWriter writer = new IndentingWriter('  ', buffer);
-    var options =
-        new GenerationOptions(
-            new CodeGeneratorRequest(), new CodeGeneratorResponse());
-    FileGenerator fg =
-        new FileGenerator(fd, null, new GenerationContext(options));
+    var options = parseGenerationOptions(
+        new CodeGeneratorRequest(), new CodeGeneratorResponse());
+    FileGenerator fg = new FileGenerator(fd, null,
+        new GenerationContext(options, new DefaultOutputConfiguration()));
     fg.generate(writer);
     expect(buffer.toString(), expected);
   });
@@ -182,11 +181,10 @@
     FileDescriptorProto fd = buildFileDescriptor(topLevelEnum: true);
     MemoryWriter buffer = new MemoryWriter();
     IndentingWriter writer = new IndentingWriter('  ', buffer);
-    var options =
-        new GenerationOptions(
-            new CodeGeneratorRequest(), new CodeGeneratorResponse());
-    FileGenerator fg =
-        new FileGenerator(fd, null, new GenerationContext(options));
+    var options = parseGenerationOptions(
+        new CodeGeneratorRequest(), new CodeGeneratorResponse());
+    FileGenerator fg = new FileGenerator(fd, null,
+        new GenerationContext(options, new DefaultOutputConfiguration()));
     fg.generate(writer);
     expect(buffer.toString(), expected);
   });
@@ -236,11 +234,10 @@
     fd.package = "pb_library";
     MemoryWriter buffer = new MemoryWriter();
     IndentingWriter writer = new IndentingWriter('  ', buffer);
-    var options =
-        new GenerationOptions(
-            new CodeGeneratorRequest(), new CodeGeneratorResponse());
-    FileGenerator fg =
-        new FileGenerator(fd, null, new GenerationContext(options));
+    var options = parseGenerationOptions(
+        new CodeGeneratorRequest(), new CodeGeneratorResponse());
+    FileGenerator fg = new FileGenerator(fd, null,
+        new GenerationContext(options, new DefaultOutputConfiguration()));
     fg.generate(writer);
     expect(buffer.toString(), expected);
   });
@@ -293,12 +290,10 @@
     request.parameter = 'field_name=PhoneNumber.number|No,'
                         'field_name=PhoneNumber.name|Name_,'
                         'field_name=PhoneNumber.type|The_type';
-    var options =
-        new GenerationOptions(
-            request, new CodeGeneratorResponse());
-    FileGenerator fg =
-        new FileGenerator(
-            fd, null, new GenerationContext(options));
+    var options = parseGenerationOptions(
+        request, new CodeGeneratorResponse());
+    FileGenerator fg = new FileGenerator(fd, null,
+        new GenerationContext(options, new DefaultOutputConfiguration()));
     fg.generate(writer);
     expect(buffer.toString(), expected);
   });
@@ -443,8 +438,10 @@
     MemoryWriter buffer = new MemoryWriter();
     IndentingWriter writer = new IndentingWriter('  ', buffer);
     var request = new CodeGeneratorRequest();
-    var options = new GenerationOptions(request, new CodeGeneratorResponse());
-    var context = new GenerationContext(options);
+    var response = new CodeGeneratorResponse();
+    var options = parseGenerationOptions(request, response);
+    var context = new GenerationContext(options,
+        new DefaultOutputConfiguration());
     new FileGenerator(fd1, null, context);
     new FileGenerator(fd2, null, context);
     FileGenerator fg = new FileGenerator(fd, null, context);
diff --git a/test/indenting_writer_test.dart b/test/indenting_writer_test.dart
index 03887eb..028f655 100755
--- a/test/indenting_writer_test.dart
+++ b/test/indenting_writer_test.dart
@@ -5,7 +5,7 @@
 
 library indenting_writer_test;
 
-import 'package:protoc-plugin/protoc.dart';
+import 'package:protoc_plugin/protoc.dart';
 import 'package:unittest/unittest.dart';
 
 void main() {
diff --git a/test/message_generator_test.dart b/test/message_generator_test.dart
index 78d48c3..39e1ed6 100755
--- a/test/message_generator_test.dart
+++ b/test/message_generator_test.dart
@@ -5,9 +5,9 @@
 
 library message_generator_test;
 
-import 'package:protoc-plugin/src/descriptor.pb.dart';
-import 'package:protoc-plugin/src/plugin.pb.dart';
-import 'package:protoc-plugin/protoc.dart';
+import 'package:protoc_plugin/src/descriptor.pb.dart';
+import 'package:protoc_plugin/src/plugin.pb.dart';
+import 'package:protoc_plugin/protoc.dart';
 import 'package:unittest/unittest.dart';
 
 void main() {
@@ -105,10 +105,10 @@
         ..enumType.add(ed);
     MemoryWriter buffer = new MemoryWriter();
     IndentingWriter writer = new IndentingWriter('  ', buffer);
-    var options =
-        new GenerationOptions(
-            new CodeGeneratorRequest(), new CodeGeneratorResponse());
-    var context = new GenerationContext(options);
+    var options = parseGenerationOptions(
+        new CodeGeneratorRequest(), new CodeGeneratorResponse());
+    var context = new GenerationContext(options,
+        new DefaultOutputConfiguration());
     FileGenerator fg = new FileGenerator(fd, null, context);
     MessageGenerator mg = new MessageGenerator(md, fg, context);
     mg.initializeFields();
diff --git a/test/protoc_options_test.dart b/test/protoc_options_test.dart
index 90aabd5..7f31424 100644
--- a/test/protoc_options_test.dart
+++ b/test/protoc_options_test.dart
@@ -5,9 +5,9 @@
 
 library file_generator_test;
 
-import 'package:protoc-plugin/src/descriptor.pb.dart';
-import 'package:protoc-plugin/src/plugin.pb.dart';
-import 'package:protoc-plugin/protoc.dart';
+import 'package:protoc_plugin/src/descriptor.pb.dart';
+import 'package:protoc_plugin/src/plugin.pb.dart';
+import 'package:protoc_plugin/protoc.dart';
 import 'package:unittest/unittest.dart';
 
 
@@ -17,10 +17,10 @@
       var request = new CodeGeneratorRequest();
       if (parameter != null) request.parameter = parameter;
       var response = new CodeGeneratorResponse();
-      var options = new GenerationOptions(request, response);
+      var options = parseGenerationOptions(request, response);
       expect(options, new isInstanceOf<GenerationOptions>());
       expect(response.error, '');
-      expect(options.fieldNameOptions, equals(expected));
+      expect(options.fieldNameOverrides, equals(expected));
     }
 
     checkValid(null, {});
@@ -41,7 +41,7 @@
       var request = new CodeGeneratorRequest();
       if (parameter != null) request.parameter = parameter;
       var response = new CodeGeneratorResponse();
-      var options = new GenerationOptions(request, response);
+      var options = parseGenerationOptions(request, response);
       expect(options, isNull);
     }