Skip to content

Commit

Permalink
Introduce Opaquer
Browse files Browse the repository at this point in the history
  • Loading branch information
oldergod committed Oct 6, 2023
1 parent 126c5f4 commit e745eb6
Show file tree
Hide file tree
Showing 11 changed files with 364 additions and 13 deletions.
275 changes: 273 additions & 2 deletions wire-compiler/src/test/java/com/squareup/wire/schema/LinkerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@
package com.squareup.wire.schema

import com.squareup.wire.testing.add
import kotlin.test.assertFailsWith
import okio.Path
import okio.Path.Companion.toPath
import okio.fakefilesystem.FakeFileSystem
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test

class LinkerTest {
private val fs = FakeFileSystem().apply {
if (Path.DIRECTORY_SEPARATOR == "\\") emulateWindows() else emulateUnix()
createDirectories("proto-path".toPath())
}

@Test
Expand Down Expand Up @@ -56,6 +59,272 @@ class LinkerTest {
)
}

@Test fun opaqueMessageDeclaredField() {
fs.add(
"source-path/cafe/cafe.proto",
"""
|syntax = "proto2";
|
|package cafe;
|
|message CafeDrink {
| optional int32 size_ounces = 1;
| repeated EspressoShot shots = 2;
|}
|
|message EspressoShot {
| optional Roast roast = 1;
| optional bool decaf = 2;
|}
|
|enum Roast {
| MEDIUM = 1;
| DARK = 2;
|}
""".trimMargin(),
)
val schema = loadAndLinkSchema(opaqueTypes = listOf(ProtoType.get("cafe.EspressoShot")))
assertThat((schema.getType("cafe.CafeDrink") as MessageType).field("shots")!!.type!!)
.isEqualTo(ProtoType.BYTES)
assertThat(schema.protoFile("cafe/cafe.proto")!!.toSchema()).isEqualTo(
"""
|// Proto schema formatted by Wire, do not edit.
|// Source: cafe/cafe.proto
|
|syntax = "proto2";
|
|package cafe;
|
|message CafeDrink {
| optional int32 size_ounces = 1;
|
| repeated bytes shots = 2;
|}
|
|message EspressoShot {
| optional Roast roast = 1;
|
| optional bool decaf = 2;
|}
|
|enum Roast {
| MEDIUM = 1;
| DARK = 2;
|}
|
""".trimMargin(),
)
}

@Test fun opaqueEnumDeclaredField() {
fs.add(
"source-path/cafe/cafe.proto",
"""
|syntax = "proto2";
|
|package cafe;
|
|message CafeDrink {
| optional int32 size_ounces = 1;
| repeated EspressoShot shots = 2;
|}
|
|message EspressoShot {
| optional Roast roast = 1;
| optional bool decaf = 2;
|}
|
|enum Roast {
| MEDIUM = 1;
| DARK = 2;
|}
""".trimMargin(),
)
val schema = loadAndLinkSchema(opaqueTypes = listOf(ProtoType.get("cafe.Roast")))
assertThat((schema.getType("cafe.EspressoShot") as MessageType).field("roast")!!.type!!)
.isEqualTo(ProtoType.BYTES)
assertThat(schema.protoFile("cafe/cafe.proto")!!.toSchema()).isEqualTo(
"""
|// Proto schema formatted by Wire, do not edit.
|// Source: cafe/cafe.proto
|
|syntax = "proto2";
|
|package cafe;
|
|message CafeDrink {
| optional int32 size_ounces = 1;
|
| repeated EspressoShot shots = 2;
|}
|
|message EspressoShot {
| optional bytes roast = 1;
|
| optional bool decaf = 2;
|}
|
|enum Roast {
| MEDIUM = 1;
| DARK = 2;
|}
|
""".trimMargin(),
)
}

@Test fun opaqueExtensionField() {
fs.add(
"source-path/cafe/cafe.proto",
"""
|syntax = "proto2";
|
|package cafe;
|
|message CafeDrink {
| optional int32 size_ounces = 1;
|}
|
|extend CafeDrink {
| repeated EspressoShot shots = 2;
|}
|
|message EspressoShot {
| optional Roast roast = 1;
| optional bool decaf = 2;
|}
|
|enum Roast {
| MEDIUM = 1;
| DARK = 2;
|}
""".trimMargin(),
)
val schema = loadAndLinkSchema(opaqueTypes = listOf(ProtoType.get("cafe.EspressoShot")))
assertThat((schema.getType("cafe.CafeDrink") as MessageType).extensionField("cafe.shots")!!.type!!)
.isEqualTo(ProtoType.BYTES)
assertThat(schema.protoFile("cafe/cafe.proto")!!.toSchema()).isEqualTo(
"""
|// Proto schema formatted by Wire, do not edit.
|// Source: cafe/cafe.proto
|
|syntax = "proto2";
|
|package cafe;
|
|message CafeDrink {
| optional int32 size_ounces = 1;
|}
|
|message EspressoShot {
| optional Roast roast = 1;
|
| optional bool decaf = 2;
|}
|
|enum Roast {
| MEDIUM = 1;
| DARK = 2;
|}
|
|extend CafeDrink {
| repeated bytes shots = 2;
|}
|
""".trimMargin(),
)
}

@Test fun opaqueMultipleFields() {
fs.add(
"source-path/cafe/cafe.proto",
"""
|syntax = "proto2";
|
|package cafe;
|
|message CafeDrink {
| optional int32 size_ounces = 1;
| repeated EspressoShot shots = 2;
|}
|
|message EspressoShot {
| optional Roast roast = 1;
| optional bool decaf = 2;
|}
|
|enum Roast {
| MEDIUM = 1;
| DARK = 2;
|}
""".trimMargin(),
)
val schema = loadAndLinkSchema(
opaqueTypes = listOf(
ProtoType.get("cafe.EspressoShot"),
ProtoType.get("cafe.Roast"),
),
)
assertThat((schema.getType("cafe.CafeDrink") as MessageType).field("shots")!!.type!!)
.isEqualTo(ProtoType.BYTES)
assertThat((schema.getType("cafe.EspressoShot") as MessageType).field("roast")!!.type!!)
.isEqualTo(ProtoType.BYTES)
assertThat(schema.protoFile("cafe/cafe.proto")!!.toSchema()).isEqualTo(
"""
|// Proto schema formatted by Wire, do not edit.
|// Source: cafe/cafe.proto
|
|syntax = "proto2";
|
|package cafe;
|
|message CafeDrink {
| optional int32 size_ounces = 1;
|
| repeated bytes shots = 2;
|}
|
|message EspressoShot {
| optional bytes roast = 1;
|
| optional bool decaf = 2;
|}
|
|enum Roast {
| MEDIUM = 1;
| DARK = 2;
|}
|
""".trimMargin(),
)
}

@Test fun opaqueScalarTypeThrows() {
fs.add(
"source-path/cafe/cafe.proto",
"""
|syntax = "proto2";
|
|package cafe;
|
|message CafeDrink {
| optional int32 size_ounces = 1;
|}
""".trimMargin(),
)

val exception = assertFailsWith<SchemaException> {
loadAndLinkSchema(opaqueTypes = listOf(ProtoType.INT32))
}
assertThat(exception).hasMessageContaining(
"""
|Scalar types like int32 cannot be opaqued
| for field size_ounces (source-path/cafe/cafe.proto:6:3)
| in message cafe.CafeDrink (source-path/cafe/cafe.proto:5:1)
""".trimMargin(),
)
}

@Test
fun unusedProtoPathFileExcludedFromSchema() {
fs.add(
Expand Down Expand Up @@ -225,15 +494,17 @@ class LinkerTest {
|}
""".trimMargin(),
)
fs.add("proto-path/b.proto", "")
val schema = loadAndLinkSchema()

val enumValueDeprecated = schema.getField(Options.ENUM_VALUE_OPTIONS, "deprecated")
assertThat(enumValueDeprecated!!.encodeMode).isNotNull()
}

private fun loadAndLinkSchema(): Schema {
private fun loadAndLinkSchema(
opaqueTypes: List<ProtoType> = listOf(),
): Schema {
val loader = SchemaLoader(fs)
loader.opaqueTypes = opaqueTypes
loader.initRoots(
sourcePath = listOf(Location.get("source-path")),
protoPath = listOf(Location.get("proto-path")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,32 @@ class WireRunTest {
.contains("public final class Red extends Message")
}

@Test
fun opaqueBeforeGeneratingKtThenJava() {
writeBlueProto()
writeTriangleProto()

val wireRun = WireRun(
sourcePath = listOf(Location.get("colors/src/main/proto")),
protoPath = listOf(Location.get("polygons/src/main/proto")),
opaqueTypes = listOf("squareup.polygons.Triangle"),
targets = listOf(
KotlinTarget(
outDirectory = "generated/kt",
),
),
)
wireRun.execute(fs, logger)

assertThat(fs.findFiles("generated")).containsExactlyInAnyOrderAsRelativePaths(
"generated/kt/squareup/colors/Blue.kt",
)
assertThat(fs.readUtf8("generated/kt/squareup/colors/Blue.kt"))
.contains("class Blue")
// The type `Triangle` has been opaqued.
.contains("public val triangle: ByteString? = null")
}

@Test
fun noSuchClassEventListener() {
assertThat(
Expand Down
10 changes: 7 additions & 3 deletions wire-schema/api/wire-schema.api
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,8 @@ public final class com/squareup/wire/schema/LinkedOptionEntry {
}

public final class com/squareup/wire/schema/Linker {
public fun <init> (Lcom/squareup/wire/schema/Loader;Lcom/squareup/wire/schema/ErrorCollector;ZZ)V
public fun <init> (Lcom/squareup/wire/schema/Loader;Lcom/squareup/wire/schema/ErrorCollector;ZZLjava/util/List;)V
public synthetic fun <init> (Lcom/squareup/wire/schema/Loader;Lcom/squareup/wire/schema/ErrorCollector;ZZLjava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun addType (Lcom/squareup/wire/schema/ProtoType;Lcom/squareup/wire/schema/Type;)V
public final fun dereference (Lcom/squareup/wire/schema/ProtoType;Ljava/lang/String;)Lcom/squareup/wire/schema/Field;
public final fun get (Lcom/squareup/wire/schema/ProtoType;)Lcom/squareup/wire/schema/Type;
Expand Down Expand Up @@ -883,6 +884,7 @@ public final class com/squareup/wire/schema/SchemaLoader : com/squareup/wire/sch
public fun <init> (Ljava/nio/file/FileSystem;)V
public fun <init> (Lokio/FileSystem;)V
public final fun getLoadExhaustively ()Z
public final fun getOpaqueTypes ()Ljava/util/List;
public final fun getPermitPackageCycles ()Z
public final fun getSourcePathFiles ()Ljava/util/List;
public final fun initRoots (Ljava/util/List;Ljava/util/List;)V
Expand All @@ -891,6 +893,7 @@ public final class com/squareup/wire/schema/SchemaLoader : com/squareup/wire/sch
public fun loadProfile (Ljava/lang/String;Lcom/squareup/wire/schema/Schema;)Lcom/squareup/wire/schema/Profile;
public final fun loadSchema ()Lcom/squareup/wire/schema/Schema;
public final fun setLoadExhaustively (Z)V
public final fun setOpaqueTypes (Ljava/util/List;)V
public final fun setPermitPackageCycles (Z)V
public synthetic fun withErrors (Lcom/squareup/wire/schema/ErrorCollector;)Lcom/squareup/wire/schema/Loader;
public fun withErrors (Lcom/squareup/wire/schema/ErrorCollector;)Lcom/squareup/wire/schema/SchemaLoader;
Expand Down Expand Up @@ -985,13 +988,14 @@ public final class com/squareup/wire/schema/WireLoggersKt {
}

public final class com/squareup/wire/schema/WireRun {
public fun <init> (Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;ZLjava/util/List;Z)V
public synthetic fun <init> (Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;ZLjava/util/List;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;ZLjava/util/List;ZLjava/util/List;)V
public synthetic fun <init> (Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;ZLjava/util/List;ZLjava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun execute (Lokio/FileSystem;Lcom/squareup/wire/WireLogger;)V
public final fun getEventListeners ()Ljava/util/List;
public final fun getModules ()Ljava/util/Map;
public final fun getMoves ()Ljava/util/List;
public final fun getOnlyVersion ()Ljava/lang/String;
public final fun getOpaqueTypes ()Ljava/util/List;
public final fun getPermitPackageCycles ()Z
public final fun getProtoPath ()Ljava/util/List;
public final fun getRejectUnusedRootsOrPrunes ()Z
Expand Down
Loading

0 comments on commit e745eb6

Please sign in to comment.