Эх сурвалжийг харах

Move `SwiftProtobufNamer` `uniquelyNamedValues(enum:)` to the plugin.

The api really is specific to generation of the proto sources and it depends on
some apis on `EnumDescriptor` that also should move out of the plugin library.

Also move the tests out to the new plugin test target.
Thomas Van Lenten 3 жил өмнө
parent
commit
1d7da61a9c

+ 1 - 1
Package.swift

@@ -75,7 +75,7 @@ let package = Package(
     ),
     .testTarget(
         name: "protoc-gen-swiftTests",
-        dependencies: ["protoc-gen-swift"]
+        dependencies: ["protoc-gen-swift", "SwiftProtobufTestHelpers"]
     ),
   ],
   swiftLanguageVersions: [.v5]

+ 0 - 26
Sources/SwiftProtobufPluginLibrary/SwiftProtobufNamer.swift

@@ -164,32 +164,6 @@ public final class SwiftProtobufNamer {
     return "." + NamingUtils.trimBackticks(relativeName)
   }
 
-  /// Filters the Enum's values to those that will have unique Swift
-  /// names. Only poorly named proto enum alias values get filtered
-  /// away, so the assumption is they aren't really needed from an
-  /// api pov.
-  public func uniquelyNamedValues(enum e: EnumDescriptor) -> [EnumValueDescriptor] {
-    return e.values.filter {
-      // Original are kept as is. The computations for relative
-      // name already adds values for collisions with different
-      // values.
-      guard let aliasOf = $0.aliasOf else { return true }
-      let relativeName = self.relativeName(enumValue: $0)
-      let aliasOfRelativeName = self.relativeName(enumValue: aliasOf)
-      // If the relative name matches for the alias and original, drop
-      // the alias.
-      guard relativeName != aliasOfRelativeName else { return false }
-      // Only include this alias if it is the first one with this name.
-      // (handles alias with different cases in their names that get
-      // mangled to a single Swift name.)
-      let firstAlias = aliasOf.aliases.firstIndex {
-        let otherRelativeName = self.relativeName(enumValue: $0)
-        return relativeName == otherRelativeName
-      }
-      return aliasOf.aliases[firstAlias!] === $0
-    }
-  }
-
   /// Calculate the relative name for the given oneof.
   public func relativeName(oneof: OneofDescriptor) -> String {
     let camelCase = NamingUtils.toUpperCamelCase(oneof.name)

+ 44 - 0
Sources/protoc-gen-swift/SwiftProtobufNamer+Extensions.swift

@@ -0,0 +1,44 @@
+// Sources/SwiftProtobufPluginLibrary/SwiftProtobufNamer.swift - A helper that generates SwiftProtobuf names.
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See LICENSE.txt for license information:
+// https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
+//
+// -----------------------------------------------------------------------------
+///
+/// A helper that can generate SwiftProtobuf names from types.
+///
+// -----------------------------------------------------------------------------
+
+import SwiftProtobufPluginLibrary
+
+extension SwiftProtobufNamer {
+
+  /// Filters the Enum's values to those that will have unique Swift
+  /// names. Only poorly named proto enum alias values get filtered
+  /// away, so the assumption is they aren't really needed from an
+  /// api pov.
+  func uniquelyNamedValues(enum e: EnumDescriptor) -> [EnumValueDescriptor] {
+    return e.values.filter {
+      // Original are kept as is. The computations for relative
+      // name already adds values for collisions with different
+      // values.
+      guard let aliasOf = $0.aliasOf else { return true }
+      let relativeName = self.relativeName(enumValue: $0)
+      let aliasOfRelativeName = self.relativeName(enumValue: aliasOf)
+      // If the relative name matches for the alias and original, drop
+      // the alias.
+      guard relativeName != aliasOfRelativeName else { return false }
+      // Only include this alias if it is the first one with this name.
+      // (handles alias with different cases in their names that get
+      // mangled to a single Swift name.)
+      let firstAlias = aliasOf.aliases.firstIndex {
+        let otherRelativeName = self.relativeName(enumValue: $0)
+        return relativeName == otherRelativeName
+      }
+      return aliasOf.aliases[firstAlias!] === $0
+    }
+  }
+}

+ 0 - 62
Tests/SwiftProtobufPluginLibraryTests/Test_SwiftProtobufNamer.swift

@@ -76,18 +76,6 @@ class Test_SwiftProtobufNamer: XCTestCase {
     XCTAssertEqual(namer.relativeName(enumValue: values[3]), "foo")
     XCTAssertEqual(namer.relativeName(enumValue: values[4]), "foo")
     XCTAssertEqual(namer.relativeName(enumValue: values[5]), "alias")
-
-    // Test uniquelyNamedValues(enum:)
-
-    let filtered = namer.uniquelyNamedValues(enum: e)
-    XCTAssertEqual(filtered.count, 3)
-
-    XCTAssertEqual(filtered[0].name, "TEST_ENUM_FOO")
-    XCTAssertEqual(filtered[1].name, "TEST_ENUM_BAR")
-    XCTAssertEqual(filtered[2].name, "TEST_ENUM_ALIAS")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[0]), "foo")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[1]), "bar")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[2]), "alias")
   }
 
   func testEnumValueHandling_NameCollisions() {
@@ -138,20 +126,6 @@ class Test_SwiftProtobufNamer: XCTestCase {
     XCTAssertEqual(namer.relativeName(enumValue: values[1]), "bar")
     XCTAssertEqual(namer.relativeName(enumValue: values[2]), "foo_2")
     XCTAssertEqual(namer.relativeName(enumValue: values[3]), "foo_n1")
-
-    // Test uniquelyNamedValues(enum:)
-
-    let filtered = namer.uniquelyNamedValues(enum: e)
-    XCTAssertEqual(filtered.count, 4)
-
-    XCTAssertEqual(filtered[0].name, "TEST_ENUM_FOO")
-    XCTAssertEqual(filtered[1].name, "TEST_ENUM_BAR")
-    XCTAssertEqual(filtered[2].name, "TESTENUM_FOO")
-    XCTAssertEqual(filtered[3].name, "_FOO")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[0]), "foo_0")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[1]), "bar")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[2]), "foo_2")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[3]), "foo_n1")
   }
 
   func testEnumValueHandling_NameCollisionsAndAliasMatches() {
@@ -225,24 +199,6 @@ class Test_SwiftProtobufNamer: XCTestCase {
     XCTAssertEqual(namer.relativeName(enumValue: values[5]), "alias")
     XCTAssertEqual(namer.relativeName(enumValue: values[6]), "mumble_1")
     XCTAssertEqual(namer.relativeName(enumValue: values[7]), "mumble_0")
-
-    // Test uniquelyNamedValues(enum:)
-
-    let filtered = namer.uniquelyNamedValues(enum: e)
-    XCTAssertEqual(filtered.count, 6)
-
-    XCTAssertEqual(filtered[0].name, "TEST_ENUM_FOO")
-    XCTAssertEqual(filtered[1].name, "TEST_ENUM_BAR")
-    XCTAssertEqual(filtered[2].name, "_FOO")
-    XCTAssertEqual(filtered[3].name, "TEST_ENUM_ALIAS")
-    XCTAssertEqual(filtered[4].name, "mumble")
-    XCTAssertEqual(filtered[5].name, "MUMBLE")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[0]), "foo_0")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[1]), "bar")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[2]), "foo_2")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[3]), "alias")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[4]), "mumble_1")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[5]), "mumble_0")
   }
 
   func testEnumValueHandling_UniqueAliasNameCollisions() {
@@ -316,24 +272,6 @@ class Test_SwiftProtobufNamer: XCTestCase {
     XCTAssertEqual(namer.relativeName(enumValue: values[3]), "qux")
     XCTAssertEqual(namer.relativeName(enumValue: values[4]), "qux")
     XCTAssertEqual(namer.relativeName(enumValue: values[5]), "bAz")
-
-    // Test uniquelyNamedValues(enum:)
-
-    // QUX & qux collided, so only one remains.
-
-    let filtered = namer.uniquelyNamedValues(enum: e)
-    XCTAssertEqual(filtered.count, 5)
-
-    XCTAssertEqual(filtered[0].name, "ALIAS_FOO")
-    XCTAssertEqual(filtered[1].name, "ALIAS_BAR")
-    XCTAssertEqual(filtered[2].name, "ALIAS_BAZ")
-    XCTAssertEqual(filtered[3].name, "QUX")
-    XCTAssertEqual(filtered[4].name, "bAz")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[0]), "aliasFoo")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[1]), "aliasBar")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[2]), "aliasBaz")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[3]), "qux")
-    XCTAssertEqual(namer.relativeName(enumValue: filtered[4]), "bAz")
   }
 
 }

+ 304 - 0
Tests/protoc-gen-swiftTests/Test_SwiftProtobufNamerExtensions.swift

@@ -0,0 +1,304 @@
+// Tests/SwiftProtobufPluginLibraryTests/Test_SwiftProtobufNamer.swift - Test SwiftProtobufNamer.swift
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See LICENSE.txt for license information:
+// https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
+//
+// -----------------------------------------------------------------------------
+
+import XCTest
+import SwiftProtobuf
+import SwiftProtobufPluginLibrary
+import SwiftProtobufTestHelpers
+@testable import protoc_gen_swift
+
+class Test_SwiftProtobufNamer: XCTestCase {
+
+  func testEnumValueHandling_AliasNameMatches() throws {
+    let txt = [
+      "name: \"test.proto\"",
+      "syntax: \"proto2\"",
+      "enum_type {",
+      "  name: \"TestEnum\"",
+      "  options {",
+      "     allow_alias: true",
+      "  }",
+      "  value {",
+      "    name: \"TEST_ENUM_FOO\"",
+      "    number: 0",  // Primary
+      "  }",
+      "  value {",
+      "    name: \"TEST_ENUM_BAR\"",
+      "    number: 1",
+      "  }",
+      "  value {",
+      "    name: \"TESTENUM_FOO\"",
+      "    number: 0",  // Alias
+      "  }",
+      "  value {",
+      "    name: \"_FOO\"",
+      "    number: 0",  // Alias
+      "  }",
+      "  value {",
+      "    name: \"FOO\"",
+      "    number: 0",  // Alias
+      "  }",
+      "  value {",
+      "    name: \"TEST_ENUM_ALIAS\"",
+      "    number: 0",  // Alias (unique name)
+      "  }",
+      "}"
+    ]
+
+    let fileProto: Google_Protobuf_FileDescriptorProto
+    do {
+     fileProto = try Google_Protobuf_FileDescriptorProto(textFormatStrings: txt)
+    } catch let e {
+      XCTFail("Error: \(e)")
+      return
+    }
+
+    let descriptorSet = DescriptorSet(protos: [fileProto])
+    let namer =
+      SwiftProtobufNamer(currentFile: descriptorSet.fileDescriptor(named: "test.proto")!,
+                         protoFileToModuleMappings: ProtoFileToModuleMappings())
+
+    let e = descriptorSet.enumDescriptor(named: "TestEnum")!
+    let values = e.values
+    XCTAssertEqual(values.count, 6)
+
+    // Test uniquelyNamedValues(enum:)
+
+    let filtered = namer.uniquelyNamedValues(enum: e)
+    XCTAssertEqual(filtered.count, 3)
+
+    XCTAssertEqual(filtered[0].name, "TEST_ENUM_FOO")
+    XCTAssertEqual(filtered[1].name, "TEST_ENUM_BAR")
+    XCTAssertEqual(filtered[2].name, "TEST_ENUM_ALIAS")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[0]), "foo")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[1]), "bar")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[2]), "alias")
+  }
+
+  func testEnumValueHandling_NameCollisions() {
+    let txt = [
+      "name: \"test.proto\"",
+      "syntax: \"proto2\"",
+      "enum_type {",
+      "  name: \"TestEnum\"",
+      "  value {",
+      "    name: \"TEST_ENUM_FOO\"",
+      "    number: 0",  // Collision
+      "  }",
+      "  value {",
+      "    name: \"TEST_ENUM_BAR\"",
+      "    number: 1",
+      "  }",
+      "  value {",
+      "    name: \"TESTENUM_FOO\"",
+      "    number: 2",  // Collision
+      "  }",
+      "  value {",
+      "    name: \"_FOO\"",
+      "    number: -1",  // Collision - negative value
+      "  }",
+      "}"
+    ]
+
+    let fileProto: Google_Protobuf_FileDescriptorProto
+    do {
+      fileProto = try Google_Protobuf_FileDescriptorProto(textFormatStrings: txt)
+    } catch let e {
+      XCTFail("Error: \(e)")
+      return
+    }
+
+    let descriptorSet = DescriptorSet(protos: [fileProto])
+    let namer =
+      SwiftProtobufNamer(currentFile: descriptorSet.fileDescriptor(named: "test.proto")!,
+                         protoFileToModuleMappings: ProtoFileToModuleMappings())
+
+    let e = descriptorSet.enumDescriptor(named: "TestEnum")!
+    let values = e.values
+    XCTAssertEqual(values.count, 4)
+
+    // Test uniquelyNamedValues(enum:)
+
+    let filtered = namer.uniquelyNamedValues(enum: e)
+    XCTAssertEqual(filtered.count, 4)
+
+    XCTAssertEqual(filtered[0].name, "TEST_ENUM_FOO")
+    XCTAssertEqual(filtered[1].name, "TEST_ENUM_BAR")
+    XCTAssertEqual(filtered[2].name, "TESTENUM_FOO")
+    XCTAssertEqual(filtered[3].name, "_FOO")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[0]), "foo_0")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[1]), "bar")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[2]), "foo_2")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[3]), "foo_n1")
+  }
+
+  func testEnumValueHandling_NameCollisionsAndAliasMatches() {
+    let txt = [
+      "name: \"test.proto\"",
+      "syntax: \"proto2\"",
+      "enum_type {",
+      "  name: \"TestEnum\"",
+      "  options {",
+      "     allow_alias: true",
+      "  }",
+      "  value {",
+      "    name: \"TEST_ENUM_FOO\"",
+      "    number: 0",  // Collision/Primary0
+      "  }",
+      "  value {",
+      "    name: \"TEST_ENUM_BAR\"",
+      "    number: 1",
+      "  }",
+      "  value {",
+      "    name: \"TESTENUM_FOO\"",
+      "    number: 0",  // Alias 0
+      "  }",
+      "  value {",
+      "    name: \"_FOO\"",
+      "    number: 2",  // Collision/Primary2
+      "  }",
+      "  value {",
+      "    name: \"FOO\"",
+      "    number: 2",  // Alias 2
+      "  }",
+      "  value {",
+      "    name: \"TEST_ENUM_ALIAS\"",
+      "    number: 0",  // Alias 0 - Unique name
+      "  }",
+      "  value {",
+      "    name: \"mumble\"",
+      "    number: 1",  // Alias 1 - Collision with next alias
+      "  }",
+      "  value {",
+      "    name: \"MUMBLE\"",
+      "    number: 0",  // Alias 0 - Collision with previous alias
+      "  }",
+      "}"
+    ]
+
+    let fileProto: Google_Protobuf_FileDescriptorProto
+    do {
+      fileProto = try Google_Protobuf_FileDescriptorProto(textFormatStrings: txt)
+    } catch let e {
+      XCTFail("Error: \(e)")
+      return
+    }
+
+    let descriptorSet = DescriptorSet(protos: [fileProto])
+    let namer =
+      SwiftProtobufNamer(currentFile: descriptorSet.fileDescriptor(named: "test.proto")!,
+                         protoFileToModuleMappings: ProtoFileToModuleMappings())
+
+    let e = descriptorSet.enumDescriptor(named: "TestEnum")!
+    let values = e.values
+    XCTAssertEqual(values.count, 8)
+
+    // Test uniquelyNamedValues(enum:)
+
+    let filtered = namer.uniquelyNamedValues(enum: e)
+    XCTAssertEqual(filtered.count, 6)
+
+    XCTAssertEqual(filtered[0].name, "TEST_ENUM_FOO")
+    XCTAssertEqual(filtered[1].name, "TEST_ENUM_BAR")
+    XCTAssertEqual(filtered[2].name, "_FOO")
+    XCTAssertEqual(filtered[3].name, "TEST_ENUM_ALIAS")
+    XCTAssertEqual(filtered[4].name, "mumble")
+    XCTAssertEqual(filtered[5].name, "MUMBLE")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[0]), "foo_0")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[1]), "bar")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[2]), "foo_2")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[3]), "alias")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[4]), "mumble_1")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[5]), "mumble_0")
+  }
+
+  func testEnumValueHandling_UniqueAliasNameCollisions() {
+    // Tests were the aliases collided in naming, but not with
+    // the original.
+
+    let txt = [
+      "name: \"test.proto\"",
+      "syntax: \"proto2\"",
+      "enum_type {",
+      "  name: \"AliasedEnum\"",
+      "  options {",
+      "     allow_alias: true",
+      "  }",
+      "  value {",
+      "    name: \"ALIAS_FOO\"",
+      "    number: 0",
+      "  }",
+      "  value {",
+      "    name: \"ALIAS_BAR\"",
+      "    number: 1",
+      "  }",
+      "  value {",
+      "    name: \"ALIAS_BAZ\"",
+      "    number: 2",
+      "  }",
+      "  value {",
+      "    name: \"QUX\"",
+      "    number: 2",  // short name merged with the next because they have the same value.
+      "  }",
+      "  value {",
+      "    name: \"qux\"",
+      "    number: 2",
+      "  }",
+      "  value {",
+      "    name: \"bAz\"",
+      "    number: 2",
+      "  }",
+      "}"
+    ]
+
+    let fileProto: Google_Protobuf_FileDescriptorProto
+    do {
+      fileProto = try Google_Protobuf_FileDescriptorProto(textFormatStrings: txt)
+    } catch let e {
+      XCTFail("Error: \(e)")
+      return
+    }
+
+    let descriptorSet = DescriptorSet(protos: [fileProto])
+    let namer =
+      SwiftProtobufNamer(currentFile: descriptorSet.fileDescriptor(named: "test.proto")!,
+                         protoFileToModuleMappings: ProtoFileToModuleMappings())
+
+    let e = descriptorSet.enumDescriptor(named: "AliasedEnum")!
+    let values = e.values
+    XCTAssertEqual(values.count, 6)
+
+    XCTAssertEqual(values[0].name, "ALIAS_FOO")
+    XCTAssertEqual(values[1].name, "ALIAS_BAR")
+    XCTAssertEqual(values[2].name, "ALIAS_BAZ")
+    XCTAssertEqual(values[3].name, "QUX")
+    XCTAssertEqual(values[4].name, "qux")
+    XCTAssertEqual(values[5].name, "bAz")
+
+    // Test uniquelyNamedValues(enum:)
+
+    // QUX & qux collided, so only one remains.
+
+    let filtered = namer.uniquelyNamedValues(enum: e)
+    XCTAssertEqual(filtered.count, 5)
+
+    XCTAssertEqual(filtered[0].name, "ALIAS_FOO")
+    XCTAssertEqual(filtered[1].name, "ALIAS_BAR")
+    XCTAssertEqual(filtered[2].name, "ALIAS_BAZ")
+    XCTAssertEqual(filtered[3].name, "QUX")
+    XCTAssertEqual(filtered[4].name, "bAz")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[0]), "aliasFoo")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[1]), "aliasBar")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[2]), "aliasBaz")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[3]), "qux")
+    XCTAssertEqual(namer.relativeName(enumValue: filtered[4]), "bAz")
+  }
+
+}