瀏覽代碼

Updated C# tests and code for TextFormat to match Java.

Jon Skeet 17 年之前
父節點
當前提交
40c2221ef4

+ 44 - 0
csharp/ProtocolBuffers.Test/TextFormatTest.cs

@@ -218,6 +218,37 @@ namespace Google.ProtocolBuffers {
       TestUtil.AssertAllExtensionsSet(builder.Build());
       TestUtil.AssertAllExtensionsSet(builder.Build());
     }
     }
 
 
+    [Test]
+    public void ParseCompatibility() {
+      string original = "repeated_float: inf\n" +
+                        "repeated_float: -inf\n" +
+                        "repeated_float: nan\n" +
+                        "repeated_float: inff\n" +
+                        "repeated_float: -inff\n" +
+                        "repeated_float: nanf\n" +
+                        "repeated_float: 1.0f\n" +
+                        "repeated_float: infinityf\n" +
+                        "repeated_float: -Infinityf\n" +
+                        "repeated_double: infinity\n" +
+                        "repeated_double: -infinity\n" +
+                        "repeated_double: nan\n";
+      string canonical = "repeated_float: Infinity\n" +
+                          "repeated_float: -Infinity\n" +
+                          "repeated_float: NaN\n" +
+                          "repeated_float: Infinity\n" +
+                          "repeated_float: -Infinity\n" +
+                          "repeated_float: NaN\n" +
+                          "repeated_float: 1\n" + // Java has 1.0; this is fine
+                          "repeated_float: Infinity\n" +
+                          "repeated_float: -Infinity\n" +
+                          "repeated_double: Infinity\n" +
+                          "repeated_double: -Infinity\n" +
+                          "repeated_double: NaN\n";
+      TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
+      TextFormat.Merge(original, builder);
+      Assert.AreEqual(canonical, builder.Build().ToString());
+    }
+
     [Test]
     [Test]
     public void ParseExotic() {
     public void ParseExotic() {
       TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
       TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
@@ -259,6 +290,19 @@ namespace Google.ProtocolBuffers {
       Assert.AreEqual(1, builder.OptionalGroup.A);
       Assert.AreEqual(1, builder.OptionalGroup.A);
     }
     }
 
 
+    [Test]
+    public void ParseComment() {
+      TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
+      TextFormat.Merge(
+        "# this is a comment\n" +
+        "optional_int32: 1  # another comment\n" +
+        "optional_int64: 2\n" +
+        "# EOF comment", builder);
+      Assert.AreEqual(1, builder.OptionalInt32);
+      Assert.AreEqual(2, builder.OptionalInt64);
+    }
+
+
     private static void AssertParseError(string error, string text) {
     private static void AssertParseError(string error, string text) {
       TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
       TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
       try {
       try {

+ 1 - 3
csharp/ProtocolBuffers/TextFormat.cs

@@ -40,8 +40,6 @@ namespace Google.ProtocolBuffers {
     /// <summary>
     /// <summary>
     /// Outputs a textual representation of <paramref name="fields" /> to <paramref name="output"/>.
     /// Outputs a textual representation of <paramref name="fields" /> to <paramref name="output"/>.
     /// </summary>
     /// </summary>
-    /// <param name="fields"></param>
-    /// <param name="output"></param>
     public static void Print(UnknownFieldSet fields, TextWriter output) {
     public static void Print(UnknownFieldSet fields, TextWriter output) {
       TextGenerator generator = new TextGenerator(output);
       TextGenerator generator = new TextGenerator(output);
       PrintUnknownFields(fields, generator);
       PrintUnknownFields(fields, generator);
@@ -564,7 +562,7 @@ namespace Google.ProtocolBuffers {
             break;
             break;
 
 
           case FieldType.Float:
           case FieldType.Float:
-            value = tokenizer.consumeFloat();
+            value = tokenizer.ConsumeFloat();
             break;
             break;
 
 
           case FieldType.Double:
           case FieldType.Double:

+ 40 - 6
csharp/ProtocolBuffers/TextTokenizer.cs

@@ -53,13 +53,18 @@ namespace Google.ProtocolBuffers {
     /// </summary>
     /// </summary>
     private int previousColumn = 0;
     private int previousColumn = 0;
 
 
-    private static Regex WhitespaceAndCommentPattern = new Regex("\\G(\\s|(#[^\\\n]*\\n))+", RegexOptions.Compiled);
-    private static Regex TokenPattern = new Regex(
+    private static readonly Regex WhitespaceAndCommentPattern = new Regex("\\G(\\s|(#.*$))+", 
+        RegexOptions.Compiled | RegexOptions.Multiline);
+    private static readonly Regex TokenPattern = new Regex(
       "\\G[a-zA-Z_][0-9a-zA-Z_+-]*|" +              // an identifier
       "\\G[a-zA-Z_][0-9a-zA-Z_+-]*|" +              // an identifier
       "\\G[0-9+-][0-9a-zA-Z_.+-]*|" +                  // a number
       "\\G[0-9+-][0-9a-zA-Z_.+-]*|" +                  // a number
-      "\\G\"([^\"\\\n\\\\]|\\\\[^\\\n])*(\"|\\\\?$)|" +    // a double-quoted string
-      "\\G\'([^\"\\\n\\\\]|\\\\[^\\\n])*(\'|\\\\?$)",      // a single-quoted string
-      RegexOptions.Compiled);
+      "\\G\"([^\"\\\n\\\\]|\\\\.)*(\"|\\\\?$)|" +    // a double-quoted string
+      "\\G\'([^\"\\\n\\\\]|\\\\.)*(\'|\\\\?$)",      // a single-quoted string
+      RegexOptions.Compiled | RegexOptions.Multiline);
+
+    private static readonly Regex DoubleInfinity = new Regex("^-?inf(inity)?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+    private static readonly Regex FloatInfinity = new Regex("^-?inf(inity)?f?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+    private static readonly Regex FloatNan = new Regex("^nanf?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
 
 
     /** Construct a tokenizer that parses tokens from the given text. */
     /** Construct a tokenizer that parses tokens from the given text. */
     public TextTokenizer(string text) {
     public TextTokenizer(string text) {
@@ -243,6 +248,18 @@ namespace Google.ProtocolBuffers {
     /// Otherwise, throw a FormatException.
     /// Otherwise, throw a FormatException.
     /// </summary>
     /// </summary>
     public double ConsumeDouble() {
     public double ConsumeDouble() {
+      // We need to parse infinity and nan separately because
+      // double.Parse() does not accept "inf", "infinity", or "nan".
+      if (DoubleInfinity.IsMatch(currentToken)) {
+        bool negative = currentToken.StartsWith("-");
+        NextToken();
+        return negative ? double.NegativeInfinity : double.PositiveInfinity;
+      }
+      if (currentToken.Equals("nan", StringComparison.InvariantCultureIgnoreCase)) {
+        NextToken();
+        return Double.NaN;
+      }
+
       try {
       try {
         double result = double.Parse(currentToken, CultureInfo.InvariantCulture);
         double result = double.Parse(currentToken, CultureInfo.InvariantCulture);
         NextToken();
         NextToken();
@@ -258,7 +275,24 @@ namespace Google.ProtocolBuffers {
     /// If the next token is a float, consume it and return its value.
     /// If the next token is a float, consume it and return its value.
     /// Otherwise, throw a FormatException.
     /// Otherwise, throw a FormatException.
     /// </summary>
     /// </summary>
-    public float consumeFloat() {
+    public float ConsumeFloat() {
+
+      // We need to parse infinity and nan separately because
+      // Float.parseFloat() does not accept "inf", "infinity", or "nan".
+      if (FloatInfinity.IsMatch(currentToken)) {
+        bool negative = currentToken.StartsWith("-");
+        NextToken();
+        return negative ? float.NegativeInfinity : float.PositiveInfinity;
+      }
+      if (FloatNan.IsMatch(currentToken)) {
+        NextToken();
+        return float.NaN;
+      }
+
+      if (currentToken.EndsWith("f")) {
+        currentToken = currentToken.TrimEnd('f');
+      }
+
       try {
       try {
         float result = float.Parse(currentToken, CultureInfo.InvariantCulture);
         float result = float.Parse(currentToken, CultureInfo.InvariantCulture);
         NextToken();
         NextToken();