Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 38 additions & 126 deletions packages/protobuf-test/src/generate-code.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import { describe, test, expect } from "@jest/globals";
import type { Int32Value, StringValue } from "@bufbuild/protobuf/wkt";
import { hasExtension } from "@bufbuild/protobuf";
import type { GenDescService } from "@bufbuild/protobuf/codegenv1";
import * as proto2_ts from "./gen/ts/extra/proto2_pb.js";
import * as proto2_js from "./gen/js/extra/proto2_pb.js";
Expand All @@ -31,151 +32,62 @@ import * as test_messages_proto3_ts from "./gen/ts/google/protobuf/test_messages
import * as test_messages_proto3_js from "./gen/js/google/protobuf/test_messages_proto3_pb.js";
import * as options_ts from "./gen/ts/extra/options_pb.js";
import * as option_usage_ts from "./gen/ts/extra/option-usage_pb.js";
import assert from "node:assert";
import { getExtension, hasExtension } from "@bufbuild/protobuf";

describe("custom options from generated code", () => {
test("can be read via extensions", () => {
const fileOptions =
option_usage_ts.fileDesc_extra_option_usage.proto.options;
assert(fileOptions);
expect(
getExtension(fileOptions, options_ts.file_option_retention_unknown),
).toBe("file option retention unknown");
expect(
getExtension(fileOptions, options_ts.file_option_retention_runtime),
).toBe("file option retention runtime");

const messageOptions = option_usage_ts.MessageWithOptionsDesc.proto.options;
assert(messageOptions);
expect(
getExtension(messageOptions, options_ts.message_option_retention_unknown),
).toBe("message option retention unknown");
expect(
getExtension(messageOptions, options_ts.message_option_retention_runtime),
).toBe("message option retention runtime");

const fieldOptions =
option_usage_ts.MessageWithOptionsDesc.fields[0].proto.options;
assert(fieldOptions);
expect(
getExtension(fieldOptions, options_ts.field_option_retention_unknown),
).toBe("field option retention unknown");
expect(
getExtension(fieldOptions, options_ts.field_option_retention_runtime),
).toBe("field option retention runtime");

const oneofOptions =
option_usage_ts.MessageWithOptionsDesc.oneofs[0].proto.options;
assert(oneofOptions);
expect(
getExtension(oneofOptions, options_ts.oneof_option_retention_unknown),
).toBe("oneof option retention unknown");
expect(
getExtension(oneofOptions, options_ts.oneof_option_retention_runtime),
).toBe("oneof option retention runtime");

const enumOptions = option_usage_ts.EnumWithOptionsDesc.proto.options;
assert(enumOptions);
expect(
getExtension(enumOptions, options_ts.enum_option_retention_unknown),
).toBe("enum option retention unknown");
expect(
getExtension(enumOptions, options_ts.enum_option_retention_runtime),
).toBe("enum option retention runtime");

const enumValueOptions =
option_usage_ts.EnumWithOptionsDesc.values[0].proto.options;
assert(enumValueOptions);
expect(
getExtension(
enumValueOptions,
options_ts.enum_value_option_retention_unknown,
),
).toBe("enum value option retention unknown");
expect(
getExtension(
enumValueOptions,
options_ts.enum_value_option_retention_runtime,
),
).toBe("enum value option retention runtime");

const serviceOptions = option_usage_ts.ServiceWithOptions.proto.options;
assert(serviceOptions);
expect(
getExtension(serviceOptions, options_ts.service_option_retention_unknown),
).toBe("service option retention unknown");
expect(
getExtension(serviceOptions, options_ts.service_option_retention_runtime),
).toBe("service option retention runtime");

const methodOptions =
option_usage_ts.ServiceWithOptions.methods[0].proto.options;
assert(methodOptions);
expect(
getExtension(methodOptions, options_ts.method_option_retention_unknown),
).toBe("method option retention unknown");
expect(
getExtension(methodOptions, options_ts.method_option_retention_runtime),
).toBe("method option retention runtime");
});
test("are unavailable for source retention options", () => {
const fileOptions =
option_usage_ts.fileDesc_extra_option_usage.proto.options;
assert(fileOptions);
expect(
test("source retention options are unavailable in generated code", () => {
const fileOptions = option_usage_ts.fileDesc_extra_option_usage.proto.options;
expect(
!!fileOptions &&
hasExtension(fileOptions, options_ts.file_option_retention_source),
).toBe(false);
).toBe(false);

const messageOptions = option_usage_ts.MessageWithOptionsDesc.proto.options;
assert(messageOptions);
expect(
const messageOptions = option_usage_ts.MessageWithOptionsDesc.proto.options;
expect(
!!messageOptions &&
hasExtension(messageOptions, options_ts.message_option_retention_source),
).toBe(false);
).toBe(false);

const fieldOptions =
option_usage_ts.MessageWithOptionsDesc.fields[0].proto.options;
assert(fieldOptions);
expect(
const fieldOptions =
option_usage_ts.MessageWithOptionsDesc.fields[0].proto.options;
expect(
!!fieldOptions &&
hasExtension(fieldOptions, options_ts.field_option_retention_source),
).toBe(false);
).toBe(false);

const oneofOptions =
option_usage_ts.MessageWithOptionsDesc.oneofs[0].proto.options;
assert(oneofOptions);
expect(
const oneofOptions =
option_usage_ts.MessageWithOptionsDesc.oneofs[0].proto.options;
expect(
!!oneofOptions &&
hasExtension(oneofOptions, options_ts.oneof_option_retention_source),
).toBe(false);
).toBe(false);

const enumOptions = option_usage_ts.EnumWithOptionsDesc.proto.options;
assert(enumOptions);
expect(
const enumOptions = option_usage_ts.EnumWithOptionsDesc.proto.options;
expect(
!!enumOptions &&
hasExtension(enumOptions, options_ts.enum_option_retention_source),
).toBe(false);
).toBe(false);

const enumValueOptions =
option_usage_ts.EnumWithOptionsDesc.values[0].proto.options;
assert(enumValueOptions);
expect(
const enumValueOptions =
option_usage_ts.EnumWithOptionsDesc.values[0].proto.options;
expect(
!!enumValueOptions &&
hasExtension(
enumValueOptions,
options_ts.enum_value_option_retention_source,
),
).toBe(false);
).toBe(false);

const serviceOptions = option_usage_ts.ServiceWithOptions.proto.options;
assert(serviceOptions);
expect(
const serviceOptions = option_usage_ts.ServiceWithOptions.proto.options;
expect(
!!serviceOptions &&
hasExtension(serviceOptions, options_ts.service_option_retention_source),
).toBe(false);
).toBe(false);

const methodOptions =
option_usage_ts.ServiceWithOptions.methods[0].proto.options;
assert(methodOptions);
expect(
const methodOptions =
option_usage_ts.ServiceWithOptions.methods[0].proto.options;
expect(
!!methodOptions &&
hasExtension(methodOptions, options_ts.method_option_retention_source),
).toBe(false);
});
).toBe(false);
});

test("ts generated code is assignable to js", () => {
Expand Down
147 changes: 147 additions & 0 deletions packages/protobuf-test/src/options.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright 2021-2024 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { describe, test, expect } from "@jest/globals";
import {
type AnyDesc,
type DescExtension,
getOption,
hasOption,
} from "@bufbuild/protobuf";
import {
enum_option_retention_runtime,
enum_option_retention_unknown,
enum_value_option_retention_runtime,
enum_value_option_retention_unknown,
field_option_retention_runtime,
field_option_retention_unknown,
file_option_retention_runtime,
file_option_retention_unknown,
message_option_retention_runtime,
message_option_retention_unknown,
method_option_retention_runtime,
method_option_retention_unknown,
oneof_option_retention_runtime,
oneof_option_retention_unknown,
service_option_retention_runtime,
service_option_retention_unknown,
} from "./gen/ts/extra/options_pb.js";
import {
EnumWithOptionsDesc,
fileDesc_extra_option_usage,
MessageWithOptionsDesc,
ServiceWithOptions,
} from "./gen/ts/extra/option-usage_pb.js";
import { Proto3MessageDesc } from "./gen/ts/extra/proto3_pb.js";

describe("hasOption()", () => {
test("supports anonymous descriptor and extension", () => {
const file: AnyDesc = fileDesc_extra_option_usage;
const ext: DescExtension = file_option_retention_runtime;
const has = hasOption(file, ext);
expect(has).toBe(true);
});
test("returns false if extendee does not match", () => {
const file = fileDesc_extra_option_usage;
const ext = oneof_option_retention_runtime;
// @ts-expect-error TS2345
const has = hasOption(file, ext);
expect(has).toBe(false);
});
test("returns false if descriptor has no options", () => {
expect(Proto3MessageDesc.proto.options).toBeUndefined();
const has = hasOption(Proto3MessageDesc, message_option_retention_runtime);
expect(has).toBe(false);
});
});

describe("getOption()", () => {
test("supports anonymous descriptor and extension", () => {
const file: AnyDesc = fileDesc_extra_option_usage;
const ext: DescExtension = file_option_retention_runtime;
const val = getOption(file, ext);
expect(val).toBe("file option retention runtime");
});
test("returns zero value if descriptor has no options", () => {
const field = Proto3MessageDesc.fields[0];
expect(field.proto.options).toBeUndefined();
const val = getOption(field, field_option_retention_runtime);
expect(val).toBe("");
});
test("returns option", () => {
const file = fileDesc_extra_option_usage;
expect(getOption(file, file_option_retention_unknown)).toBe(
"file option retention unknown",
);
expect(getOption(file, file_option_retention_runtime)).toBe(
"file option retention runtime",
);

const message = MessageWithOptionsDesc;
expect(getOption(message, message_option_retention_unknown)).toBe(
"message option retention unknown",
);
expect(getOption(message, message_option_retention_runtime)).toBe(
"message option retention runtime",
);

const field = MessageWithOptionsDesc.fields[0];
expect(getOption(field, field_option_retention_unknown)).toBe(
"field option retention unknown",
);
expect(getOption(field, field_option_retention_runtime)).toBe(
"field option retention runtime",
);

const oneof = MessageWithOptionsDesc.oneofs[0];
expect(getOption(oneof, oneof_option_retention_unknown)).toBe(
"oneof option retention unknown",
);
expect(getOption(oneof, oneof_option_retention_runtime)).toBe(
"oneof option retention runtime",
);

const enumeration = EnumWithOptionsDesc;
expect(getOption(enumeration, enum_option_retention_unknown)).toBe(
"enum option retention unknown",
);
expect(getOption(enumeration, enum_option_retention_runtime)).toBe(
"enum option retention runtime",
);

const enumValue = EnumWithOptionsDesc.values[0];
expect(getOption(enumValue, enum_value_option_retention_unknown)).toBe(
"enum value option retention unknown",
);
expect(getOption(enumValue, enum_value_option_retention_runtime)).toBe(
"enum value option retention runtime",
);

const service = ServiceWithOptions;
expect(getOption(service, service_option_retention_unknown)).toBe(
"service option retention unknown",
);
expect(getOption(service, service_option_retention_runtime)).toBe(
"service option retention runtime",
);

const method = ServiceWithOptions.methods[0];
expect(getOption(method, method_option_retention_unknown)).toBe(
"method option retention unknown",
);
expect(getOption(method, method_option_retention_runtime)).toBe(
"method option retention runtime",
);
});
});
Loading