mirror of
https://github.com/hanzoai/protobuf.js.git
synced 2026-09-24 17:02:08 +00:00
286 lines
16 KiB
JavaScript
286 lines
16 KiB
JavaScript
var tape = require("tape");
|
|
var protobuf = require("..");
|
|
|
|
tape.test("Options", function (test) {
|
|
var root = protobuf.loadSync("tests/data/options_test.proto");
|
|
|
|
test.test(test.name + " - field options (Int)", function (test) {
|
|
var TestFieldOptionsInt = root.lookup("TestFieldOptionsInt");
|
|
test.equal(TestFieldOptionsInt.fields.field1.options["(fo_rep_int)"], 2, "should take second repeated int option");
|
|
test.same(TestFieldOptionsInt.fields.field1.parsedOptions, [{"(fo_rep_int)": 1}, {"(fo_rep_int)": 2}], "should take all repeated int option");
|
|
|
|
test.equal(TestFieldOptionsInt.fields.field2.options["(fo_single_int)"], 3, "should correctly parse single int option");
|
|
test.same(TestFieldOptionsInt.fields.field2.parsedOptions, [{"(fo_single_int)": 3}], "should correctly parse single int option");
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - message options (Int)", function (test) {
|
|
var TestMessageOptionsInt = root.lookup("TestMessageOptionsInt");
|
|
test.equal(TestMessageOptionsInt.options["(mo_rep_int)"], 2, "should take second repeated int message option");
|
|
test.equal(TestMessageOptionsInt.options["(mo_single_int)"], 3, "should correctly parse single int message option");
|
|
test.same(TestMessageOptionsInt.parsedOptions, [{"(mo_rep_int)": 1}, {"(mo_rep_int)": 2}, {"(mo_single_int)": 3}], "should take all int message option");
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - field options (Message)", function (test) {
|
|
var TestFieldOptionsMsg = root.lookup("TestFieldOptionsMsg");
|
|
test.equal(TestFieldOptionsMsg.fields.field1.options["(fo_rep_msg).value"], 4, "should take second repeated message option");
|
|
test.equal(TestFieldOptionsMsg.fields.field1.options["(fo_rep_msg).rep_value"], 6, "should take second repeated int in second repeated option");
|
|
test.same(TestFieldOptionsMsg.fields.field1.parsedOptions, [
|
|
{"(fo_rep_msg)": {value: 1, rep_value: [2, 3]}},
|
|
{"(fo_rep_msg)": {value: 4, rep_value: [5, 6]}}], "should take all repeated message option");
|
|
test.equal(TestFieldOptionsMsg.fields.field2.options["(fo_single_msg).value"], 7, "should correctly parse single msg option");
|
|
test.equal(TestFieldOptionsMsg.fields.field2.options["(fo_single_msg).rep_value"], 9, "should take second repeated int in single msg option");
|
|
test.same(TestFieldOptionsMsg.fields.field2.parsedOptions, [{"(fo_single_msg)": {value: 7, rep_value: [8,9]}}], "should take all repeated message option");
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - message options (Message)", function (test) {
|
|
var TestMessageOptionsMsg = root.lookup("TestMessageOptionsMsg");
|
|
test.equal(TestMessageOptionsMsg.options["(mo_rep_msg).value"], 5, "should take last repeated message option");
|
|
test.equal(TestMessageOptionsMsg.options["(mo_rep_msg).rep_value"], 8, "should take last repeated int in last repeated option");
|
|
test.equal(TestMessageOptionsMsg.options["(mo_single_msg).value"], 7, "should correctly parse single msg option");
|
|
test.equal(TestMessageOptionsMsg.options["(mo_single_msg).rep_value"], 9, "should take second repeated int in single msg option");
|
|
test.same(TestMessageOptionsMsg.parsedOptions, [
|
|
{"(mo_rep_msg)": {value: 1, rep_value: [2, 3]}},
|
|
{"(mo_rep_msg)": {value: 4, rep_value: [5, 6]}},
|
|
{"(mo_rep_msg)": {value: 5, rep_value: [7, 8]}},
|
|
{"(mo_single_msg)": {value: 7, rep_value: [8, 9]}},
|
|
], "should take all message options");
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - field options (Nested)", function (test) {
|
|
var TestFieldOptionsNested = root.lookup("TestFieldOptionsNested");
|
|
test.equal(TestFieldOptionsNested.fields.field1.options["(fo_rep_msg).value"], 1, "should merge repeated options messages");
|
|
test.equal(TestFieldOptionsNested.fields.field1.options["(fo_rep_msg).rep_value"], 3, "should parse in any order");
|
|
test.equal(TestFieldOptionsNested.fields.field1.options["(fo_rep_msg).nested.nested.value"], "x", "should correctly parse nested field options");
|
|
test.equal(TestFieldOptionsNested.fields.field1.options["(fo_rep_msg).rep_nested.value"], "z", "should take second repeated nested options");
|
|
test.equal(TestFieldOptionsNested.fields.field1.options["(fo_rep_msg).nested.value"], "w", "should merge nested options");
|
|
test.same(TestFieldOptionsNested.fields.field1.parsedOptions,[
|
|
{"(fo_rep_msg)": {value: 1, nested: { nested: { value: "x"}}, rep_nested: [{value: "y"},{value: "z"}], rep_value: 3}},
|
|
{"(fo_rep_msg)": { nested: { value: "w"}}},
|
|
],"should parse all options including nested");
|
|
|
|
test.equal(TestFieldOptionsNested.fields.field2.options["(fo_single_msg).nested.value"], "x", "should correctly parse nested property name");
|
|
test.equal(TestFieldOptionsNested.fields.field2.options["(fo_single_msg).rep_nested.value"], "y", "should take second repeated nested options");
|
|
test.same(TestFieldOptionsNested.fields.field2.parsedOptions, [{
|
|
"(fo_single_msg)": {
|
|
nested: {value: "x"},
|
|
rep_nested: [{value: "x"}, {value: "y"}]
|
|
}
|
|
}
|
|
], "should parse single nested option correctly");
|
|
|
|
test.equal(TestFieldOptionsNested.fields.field3.options["(fo_single_msg).nested.value"], "x", "should correctly parse nested field options");
|
|
test.equal(TestFieldOptionsNested.fields.field3.options["(fo_single_msg).nested.nested.nested.value"], "y", "should correctly parse several nesting levels");
|
|
test.same(TestFieldOptionsNested.fields.field3.parsedOptions, [{
|
|
"(fo_single_msg)": {
|
|
nested: {
|
|
value: "x",
|
|
nested: {nested: {value: "y"}}
|
|
}
|
|
}
|
|
}], "should correctly parse several nesting levels");
|
|
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - message options (Nested)", function (test) {
|
|
var TestMessageOptionsNested = root.lookup("TestMessageOptionsNested");
|
|
test.equal(TestMessageOptionsNested.options["(mo_rep_msg).value"], 1, "should merge repeated options messages");
|
|
test.equal(TestMessageOptionsNested.options["(mo_rep_msg).rep_value"], 3, "should parse in any order");
|
|
test.equal(TestMessageOptionsNested.options["(mo_rep_msg).nested.nested.value"], "x", "should correctly parse nested field options");
|
|
test.equal(TestMessageOptionsNested.options["(mo_rep_msg).rep_nested.value"], "z", "should take second repeated nested options");
|
|
test.equal(TestMessageOptionsNested.options["(mo_rep_msg).nested.value"], "w", "should merge nested options");
|
|
|
|
test.equal(TestMessageOptionsNested.options["(mo_single_msg).nested.value"], "x", "should correctly parse nested property name");
|
|
test.equal(TestMessageOptionsNested.options["(mo_single_msg).rep_nested.value"], "y", "should take second repeated nested options");
|
|
test.equal(TestMessageOptionsNested.options["(mo_single_msg).rep_nested.nested.nested.value"], "y", "should correctly parse several nesting levels");
|
|
|
|
test.same(TestMessageOptionsNested.parsedOptions, [
|
|
{
|
|
"(mo_rep_msg)": {
|
|
value: 1,
|
|
nested: {nested: {value: "x"}},
|
|
rep_nested: [{value: "y"}, {value: "z"}],
|
|
rep_value: 3
|
|
}
|
|
},
|
|
{"(mo_rep_msg)": {nested: {value: "w"}}},
|
|
{
|
|
"(mo_single_msg)": {
|
|
nested: {value: "x"},
|
|
rep_nested: [{value: "x", nested: {nested: {value: "y"}}}, {value: "y"}]
|
|
}
|
|
}
|
|
], "should correctly parse all nested message options");
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - rpc options (Nested)", function (test) {
|
|
var TestOptionsRpc = root.lookup("TestOptionsRpc");
|
|
test.equal(TestOptionsRpc.options["(method_rep_msg).value"], 1, "should merge repeated options messages");
|
|
test.equal(TestOptionsRpc.options["(method_rep_msg).rep_value"], 3, "should parse in any order");
|
|
test.equal(TestOptionsRpc.options["(method_rep_msg).nested.nested.value"], "x", "should correctly parse nested field options");
|
|
test.equal(TestOptionsRpc.options["(method_rep_msg).rep_nested.value"], "z", "should take second repeated nested options");
|
|
test.equal(TestOptionsRpc.options["(method_rep_msg).nested.value"], "w", "should merge nested options");
|
|
|
|
test.equal(TestOptionsRpc.options["(method_single_msg).nested.value"], "x", "should correctly parse nested property name");
|
|
test.equal(TestOptionsRpc.options["(method_single_msg).rep_nested.value"], "y", "should take second repeated nested options");
|
|
test.equal(TestOptionsRpc.options["(method_single_msg).rep_nested.nested.nested.value"], "y", "should correctly parse several nesting levels");
|
|
|
|
var expectedParsedOptions = [
|
|
{
|
|
"(method_rep_msg)": {
|
|
value: 1,
|
|
empty_repeated: [],
|
|
nested: {nested: {value: "x"}},
|
|
rep_nested: [{value: "y"}, {value: "z"}],
|
|
rep_value: 3
|
|
}
|
|
},
|
|
{"(method_rep_msg)": {nested: {value: "w"}}},
|
|
{
|
|
"(method_single_msg)": {
|
|
nested: {value: "x"},
|
|
rep_nested: [{value: "x", nested: {nested: {value: "y"}}}, {value: "y"}]
|
|
}
|
|
}
|
|
];
|
|
|
|
test.same(TestOptionsRpc.parsedOptions, expectedParsedOptions, "should correctly parse all nested message options");
|
|
test.equal(TestOptionsRpc.options["(method_rep_msg).empty_repeated"], undefined, "should not set a last value for empty repeated options");
|
|
var jsonTestOptionsRpc = TestOptionsRpc.toJSON();
|
|
test.same(jsonTestOptionsRpc.parsedOptions, expectedParsedOptions, "should correctly store all nested method options in JSON");
|
|
var rootFromJson = protobuf.Root.fromJSON(root.toJSON());
|
|
var TestOptionsRpcFromJson = rootFromJson.lookup("TestOptionsRpc");
|
|
test.same(TestOptionsRpcFromJson.parsedOptions, expectedParsedOptions, "should correctly read all nested method options from JSON");
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - invalid option", function (test) {
|
|
test.throws(() => { protobuf.parse("option (foo).whatever = {")});
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - unterminated option name", function (test) {
|
|
test.throws(() => { protobuf.parse('option foo')});
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - reserved aggregate option keys", function(test) {
|
|
var parsed = protobuf.parse(
|
|
"syntax = \"proto2\";" +
|
|
"message Test {" +
|
|
" optional string value = 1 [(foo) = { __proto__: \"x\" regular: \"y\" }];" +
|
|
"}"
|
|
);
|
|
var field = parsed.root.lookupType("Test").fields.value;
|
|
var option = field.parsedOptions[0]["(foo)"];
|
|
|
|
test.equal(Object.getPrototypeOf(option), Object.prototype, "should keep the aggregate option object shape");
|
|
test.notOk(Object.prototype.hasOwnProperty.call(option, "__proto__"), "should ignore reserved aggregate option keys");
|
|
test.equal(option.regular, "y", "should keep regular aggregate option keys");
|
|
test.equal(Object.getPrototypeOf(field.options), Object.prototype, "should keep the flat options prototype");
|
|
test.equal(field.options["(foo).regular"], "y", "should keep regular flat option keys");
|
|
test.equal(field.options["(foo).__proto__"], "x", "should keep extension option keys as literals");
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - aggregate option special field names", function(test) {
|
|
var root = protobuf.parse(
|
|
"syntax = \"proto2\";" +
|
|
"message Test {" +
|
|
" option (foo) = {" +
|
|
" regular: 1" +
|
|
" [pkg.ext] { enabled: true }" +
|
|
" [pkg.scalar]: \"x\"" +
|
|
" };" +
|
|
"}"
|
|
).root;
|
|
var message = root.lookupType("Test"),
|
|
option = message.parsedOptions[0]["(foo)"];
|
|
|
|
test.same(option, {
|
|
regular: 1,
|
|
"[pkg.ext]": { enabled: true },
|
|
"[pkg.scalar]": "x"
|
|
}, "should preserve bracketed special field names");
|
|
test.equal(message.options["(foo).regular"], 1, "should keep regular flat option key");
|
|
test.equal(message.options["(foo).[pkg.ext].enabled"], true, "should keep nested special flat option key");
|
|
test.equal(message.options["(foo).[pkg.scalar]"], "x", "should keep scalar special flat option key");
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - aggregate option Any type URL", function(test) {
|
|
var root = protobuf.parse(
|
|
"syntax = \"proto2\";" +
|
|
"message Test {" +
|
|
" option (foo) = {" +
|
|
" any {" +
|
|
" [type.googleapis.com/pkg.Embedded] { s: \"x\" }" +
|
|
" }" +
|
|
" };" +
|
|
"}"
|
|
).root;
|
|
var message = root.lookupType("Test"),
|
|
option = message.parsedOptions[0]["(foo)"];
|
|
|
|
test.same(option, {
|
|
any: { "[type.googleapis.com/pkg.Embedded]": { s: "x" } }
|
|
}, "should preserve the Any type URL as a bracketed field name");
|
|
test.equal(message.options["(foo).any.[type.googleapis.com/pkg.Embedded].s"], "x", "should keep the type URL in the flat option key");
|
|
|
|
// Like protoc, the type name is the segment after the last "/" and the URL
|
|
// prefix is opaque, so a multi-segment prefix parses and is preserved as-is.
|
|
var multi = protobuf.parse(
|
|
"syntax = \"proto2\";" +
|
|
"message Test2 {" +
|
|
" option (foo) = { any { [example.com/a/b/pkg.Embedded] { s: \"y\" } } };" +
|
|
"}"
|
|
).root.lookupType("Test2").parsedOptions[0]["(foo)"];
|
|
test.same(multi, {
|
|
any: { "[example.com/a/b/pkg.Embedded]": { s: "y" } }
|
|
}, "should accept and preserve a multi-slash type URL prefix");
|
|
test.end();
|
|
});
|
|
|
|
test.test(test.name + " - aggregate option arrays", function(test) {
|
|
var root = protobuf.parse(
|
|
"syntax = \"proto2\";" +
|
|
"message Test {" +
|
|
" optional string value = 1 [(foo) = {" +
|
|
" rules: [" +
|
|
" { field: \"id\" }," +
|
|
" { field: \"display_name\" }" +
|
|
" ]" +
|
|
" }];" +
|
|
"}"
|
|
).root;
|
|
var field = root.lookupType("Test").fields.value,
|
|
option = field.parsedOptions[0]["(foo)"];
|
|
|
|
test.same(option, {
|
|
rules: [
|
|
{ field: "id" },
|
|
{ field: "display_name" }
|
|
]
|
|
}, "should preserve aggregate option arrays");
|
|
test.equal(field.options["(foo).rules.field"], "display_name", "should keep the last repeated aggregate field in flat options");
|
|
test.end();
|
|
});
|
|
|
|
test.end();
|
|
});
|
|
|
|
tape.test("json_name field option", function(test) {
|
|
var root = protobuf.parse('syntax = "proto3"; message Test { string user_name = 1 [json_name = "customUserName"]; }').root;
|
|
var field = root.lookupType("Test").fields.userName;
|
|
|
|
test.equal(field.jsonName, "customUserName", "should populate Field#jsonName");
|
|
test.equal(field.options.json_name, "customUserName", "should preserve the declared field option");
|
|
test.same(field.parsedOptions, [{ json_name: "customUserName" }], "should preserve parsed option metadata");
|
|
test.end();
|
|
});
|