use insta::assert_debug_snapshot;
use prost_types::FileDescriptorProto;
use crate::error::ParseErrorKind::{self, *};
fn parse(source: &str) -> Result<FileDescriptorProto, Vec<ParseErrorKind>> {
crate::parse("test.proto", source).map_err(|err| err.into_inner())
}
#[test]
fn error_fmt_debug() {
let error = crate::parse("foo.proto", "message {}").unwrap_err();
assert_eq!(error.file(), "foo.proto");
assert_eq!(error.span(), Some(8..9));
assert_eq!(
format!("{:?}", error),
"foo.proto:1:9: expected an identifier, but found '{'"
);
}
#[test]
fn parse_field_default() {
assert_debug_snapshot!(parse(
"
message Foo {
optional int32 enum = 1 [default = 2.4];
}
"
));
assert_debug_snapshot!(parse(
"
message Foo {
optional Enum enum = 1 [default = ONE];
}
enum Enum {}
"
));
}
#[test]
fn negative_ident_outside_default() {
assert_debug_snapshot!(parse(
"
option opt = -foo;
"
));
}
#[test]
fn map_field_invalid_type() {
assert_eq!(
parse(
r#"message Message {
map<Message, sfixed32> field = 1;
}"#
),
Err(vec![InvalidMapFieldKeyType { span: 34..41 }]),
);
assert_eq!(
parse(
r#"message Message {
map<.Message, fixed32> field = 1;
}"#
),
Err(vec![InvalidMapFieldKeyType { span: 34..42 }]),
);
assert_eq!(
parse(
r#"message Message {
map<.Message, bool> field = 1;
}"#
),
Err(vec![InvalidMapFieldKeyType { span: 34..42 }]),
);
assert_eq!(
parse(
r#"message Message {
map<float, string> field = 1;
}"#
),
Err(vec![InvalidMapFieldKeyType { span: 34..39 }]),
);
assert_eq!(
parse(
r#"message Message {
map<double, int64> field = 1;
}"#
),
Err(vec![InvalidMapFieldKeyType { span: 34..40 }]),
);
assert_eq!(
parse(
r#"message Message {
map<Enum, int64> field = 1;
enum Enum {
ZERO = 0;
}
}"#
),
Err(vec![InvalidMapFieldKeyType { span: 34..38 }]),
);
assert_debug_snapshot!(parse(
r#"message Message {
map<int64, float> int64 = 1;
map<uint32, double> uint32 = 2;
map<uint64, .Message> uint64 = 3;
map<sint32, Message> sint32 = 4;
map<sint64, bytes> sint64 = 5;
map<fixed32, int64> fixed32 = 6;
map<fixed64, uint32> fixed64 = 7;
map<sfixed32, sint32> sfixed32 = 8;
map<sfixed64, sint64> sfixed64 = 9;
map<bool, fixed32> bool = 10;
map<string, fixed64> string = 11;
}"#
));
}
#[test]
fn invalid_message_number() {
assert_eq!(
parse("message Foo { optional int32 i = -5; }"),
Err(vec![InvalidMessageNumber { span: 33..35 }])
);
assert_eq!(
parse("message Foo { optional int32 i = 0; }"),
Err(vec![InvalidMessageNumber { span: 33..34 }])
);
assert_eq!(
parse("message Foo { optional int32 i = 536870912; }"),
Err(vec![InvalidMessageNumber { span: 33..42 }])
);
assert_debug_snapshot!(parse("message Foo { optional int32 i = 1; }"));
assert_debug_snapshot!(parse("message Foo { optional int32 i = 536870911; }"));
assert_debug_snapshot!(parse("message Foo { optional int32 i = 18999; }"));
assert_debug_snapshot!(parse("message Foo { optional int32 i = 20000; }"));
}
#[test]
fn proto3_default_value() {
assert_eq!(
parse(
r#"
syntax = 'proto3';
message Message {
optional int32 foo = 1 [default = -0];
}"#
),
Err(vec![Proto3DefaultValue { span: 103..115 }]),
);
}
#[test]
fn map_field_with_label() {
assert_eq!(
parse(
r#"message Message {
optional map<int32, string> field = 1;
}"#
),
Err(vec![MapFieldWithLabel { span: 30..38 }]),
);
assert_eq!(
parse(
r#"
syntax = 'proto3';
message Message {
required map<int32, string> field = 1;
}"#
),
Err(vec![MapFieldWithLabel { span: 79..87 }]),
);
}
#[test]
fn message_reserved_range_extrema() {
assert_eq!(
parse(
r#"message Message {
reserved 0 to 1;
}"#
),
Err(vec![InvalidMessageNumber { span: 43..44 }]),
);
assert_eq!(
parse(
r#"message Message {
reserved 1 to 536870912;
}"#
),
Err(vec![InvalidMessageNumber { span: 48..57 }]),
);
assert_debug_snapshot!(parse(
r#"message Message {
reserved 1 to 536870911;
}"#
));
}
#[test]
fn extend_required_field() {
assert_eq!(
parse(
r#"
message Message {
extensions 1;
}
extend Message {
required int32 foo = 1;
}
"#
),
Err(vec![RequiredExtendField { span: 121..129 }]),
);
}
#[test]
fn extend_map_field() {
assert_eq!(
parse(
r#"
message Message {
extensions 1;
}
extend Message {
map<int32, string> foo = 1;
}
"#
),
Err(vec![InvalidExtendFieldKind {
kind: "map",
span: 121..148,
}]),
);
}
#[test]
fn proto3_group_field() {
assert_eq!(
parse(
r#"
syntax = 'proto3';
message Message {
optional group Foo = 1 {};
}
"#
),
Err(vec![Proto3GroupField { span: 79..104 }]),
);
}
#[test]
fn proto3_required_field() {
assert_eq!(
parse(
r#"
syntax = 'proto3';
message Message {
required int32 foo = 1;
}
"#
),
Err(vec![Proto3RequiredField { span: 79..87 }]),
);
}
#[test]
fn proto2_field_missing_label() {
assert_eq!(
parse(
r#"
syntax = 'proto2';
message Message {
int32 foo = 1;
}
"#
),
Err(vec![Proto2FieldMissingLabel { span: 79..93 }]),
);
}
#[test]
fn oneof_field_with_label() {
assert_eq!(
parse(
r#"
syntax = 'proto3';
message Message {
oneof foo {
optional int32 bar = 1;
}
}
"#
),
Err(vec![OneofFieldWithLabel { span: 111..119 }]),
);
}
#[test]
fn oneof_map_field() {
assert_eq!(
parse(
r#"
syntax = 'proto3';
message Message {
oneof foo {
map<int32, bytes> bar = 1;
}
}
"#
),
Err(vec![InvalidOneofFieldKind {
kind: "map",
span: 111..137,
}]),
);
}
#[test]
fn empty_oneof() {
assert_eq!(
parse(
r#"
syntax = 'proto3';
message Message {
oneof foo {}
}
"#
),
Err(vec![EmptyOneof { span: 79..91 }]),
);
}
#[test]
fn enum_value_extrema() {
assert_eq!(
parse(
r#"
syntax = "proto3";
enum Extreme {
ZERO = 0;
MIN = -2147483649;
MAX = 2147483648;
}
"#
),
Err(vec![
InvalidEnumNumber { span: 108..119 },
InvalidEnumNumber { span: 143..153 }
]),
);
assert_debug_snapshot!(parse(
r#"
syntax = "proto3";
enum Extreme {
ZERO = 0;
MIN = -2147483648;
MAX = 2147483647;
}
"#
));
}
#[test]
fn enum_reserved_range_extrema() {
assert_eq!(
parse(
r#"
syntax = "proto3";
enum Extreme {
ZERO = 0;
reserved -2147483649 to -1, 1 to 2147483648;
}
"#
),
Err(vec![
InvalidEnumNumber { span: 112..123 },
InvalidEnumNumber { span: 136..146 }
]),
);
assert_debug_snapshot!(parse(
r#"
syntax = "proto3";
enum Extreme {
ZERO = 0;
reserved -2147483648 to -1, 1 to 2147483647;
}
"#
));
}
#[test]
fn message_field_json_name() {
assert_eq!(
parse(
r#"message Message {
optional int32 field = 1 [json_name = "\xFF"];
}"#
),
Err(vec![InvalidUtf8String { span: 68..74 }]),
);
assert_debug_snapshot!(parse(
r#"message Message {
optional int32 field = 1 [json_name = '$FIELD'];
}"#
));
}
#[test]
fn field_default_value() {
assert_debug_snapshot!(parse(
r#"
message Message {
optional Message foo = 1 [default = ""];
}"#
));
assert_eq!(
parse(
r#"
message Message {
map<uint32, sfixed64> foo = 1 [default = ""];
}"#
),
Err(vec![InvalidDefault {
kind: "map",
span: 78..90,
}]),
);
assert_eq!(
parse(
r#"
message Message {
optional group Foo = 1 [default = ""] {};
}"#
),
Err(vec![InvalidDefault {
kind: "group",
span: 71..83,
}]),
);
assert_eq!(
parse(
r#"
message Message {
repeated int32 foo = 1 [default = 1];
}"#
),
Err(vec![InvalidDefault {
kind: "repeated",
span: 71..82,
}]),
);
assert_debug_snapshot!(parse(
r#"
message Message {
optional float default_float_exp = 23 [ default = 9e6];
optional double default_double_exp = 24 [ default = 9e22];
}
"#
));
}
#[test]
fn field_default_invalid_type() {
assert_eq!(
parse(
r#"
message Message {
optional int32 foo = 1 [default = "foo"];
}"#
),
Err(vec![ValueInvalidType {
expected: "an integer".to_owned(),
actual: "foo".to_owned(),
span: 81..86,
}]),
);
assert_eq!(
parse(
r#"
message Message {
optional uint32 foo = 1 [default = -100];
}"#
),
Err(vec![IntegerValueOutOfRange {
expected: "an unsigned 32-bit integer".to_owned(),
actual: "-100".to_owned(),
min: "0".to_owned(),
max: "4294967295".to_owned(),
span: 82..86,
}]),
);
assert_eq!(
parse(
r#"
message Message {
optional int32 foo = 1 [default = 2147483648];
}"#
),
Err(vec![IntegerValueOutOfRange {
expected: "a signed 32-bit integer".to_owned(),
actual: "2147483648".to_owned(),
min: "-2147483648".to_owned(),
max: "2147483647".to_owned(),
span: 81..91,
}]),
);
assert_debug_snapshot!(parse(
r#"
message Message {
optional Foo foo = 1 [default = 1];
}
enum Foo {
ZERO = 0;
}"#
));
assert_debug_snapshot!(parse(
r#"
message Message {
optional Foo foo = 1 [default = "ZERO"];
}
enum Foo {
ZERO = 0;
}"#
));
assert_eq!(
parse(
r#"
message Message {
optional bool foo = 1 [default = FALSE];
}"#
),
Err(vec![ValueInvalidType {
expected: "either 'true' or 'false'".to_owned(),
actual: "FALSE".to_owned(),
span: 80..85,
}]),
);
assert_debug_snapshot!(parse(
r#"
message Message {
optional Foo foo = 1 [default = FALSE];
}
enum Foo {
ZERO = 0;
}"#
));
assert_eq!(
parse(
r#"
message Message {
optional bool foo = 1 [default = -false];
}
enum Foo {
ZERO = 0;
}"#
),
Err(vec![ValueInvalidType {
expected: "either 'true' or 'false'".to_owned(),
actual: "-false".to_owned(),
span: 80..86,
}]),
);
assert_eq!(
parse(
r"
message Message {
optional string foo = 1 [default = '\xFF'];
}"
),
Err(vec![InvalidUtf8String { span: 82..88 }]),
);
assert_eq!(
parse(
r#"
message Message {
optional fixed64 foo = 1 [default = -5];
}"#
),
Err(vec![IntegerValueOutOfRange {
expected: "an unsigned 64-bit integer".to_owned(),
actual: "-5".to_owned(),
span: 83..85,
min: "0".to_owned(),
max: "18446744073709551615".to_owned()
}]),
);
assert_eq!(
parse(
r#"
message Message {
optional int32 foo = 1 [default = 5.0];
}"#
),
Err(vec![ValueInvalidType {
expected: "an integer".to_owned(),
actual: "5.0".to_owned(),
span: 81..84,
}]),
);
assert_debug_snapshot!(parse(
r#"
message Message {
optional double foo = 1 [default = nan];
optional float foo = 1 [default = -inf];
}"#
));
assert_eq!(
parse(
r#"
message Message {
optional double foo = 1 [default = ident];
}"#
),
Err(vec![ValueInvalidType {
expected: "a floating-point number".to_owned(),
actual: "ident".to_owned(),
span: 82..87,
}]),
);
assert_eq!(
parse(
r#"
message Message {
optional double foo = 1 [default = {a:0}];
}"#
),
Err(vec![ValueInvalidType {
expected: "a floating-point number".to_owned(),
actual: "a : 0".to_owned(),
span: 82..87,
}]),
);
assert_eq!(
parse(
r#"
message Message {
optional double foo = 1 [default = "abc"];
}"#
),
Err(vec![ValueInvalidType {
expected: "a floating-point number".to_owned(),
actual: "abc".to_owned(),
span: 82..87,
}]),
);
assert_eq!(
parse(
r#"
message Message {
optional sint64 foo = 1 [default = 13835058055282163711];
}"#
),
Err(vec![IntegerValueOutOfRange {
expected: "a signed 64-bit integer".to_owned(),
actual: "13835058055282163711".to_owned(),
span: 82..102,
min: "-9223372036854775808".to_owned(),
max: "9223372036854775807".to_owned()
}]),
);
assert_eq!(
parse(
r#"
message Message {
optional string foo = 1 [default = 123];
}"#
),
Err(vec![ValueInvalidType {
expected: "a string".to_owned(),
actual: "123".to_owned(),
span: 82..85,
}]),
);
assert_eq!(
parse(
r#"
message Message {
optional bytes foo = 1 [default = 123];
}"#
),
Err(vec![ValueInvalidType {
expected: "a string".to_owned(),
actual: "123".to_owned(),
span: 81..84,
}]),
);
}
#[test]
fn syntax() {
assert_debug_snapshot!(parse(""));
assert_debug_snapshot!(parse("syntax = 'proto2';"));
assert_debug_snapshot!(parse("syntax = 'proto3';"));
}
#[test]
fn imports() {
assert_debug_snapshot!(parse("import 'foo.proto';"));
assert_debug_snapshot!(parse("import weak 'foo.proto';"));
assert_debug_snapshot!(parse("import public 'foo.proto';"));
}
#[test]
fn reserved_range() {
assert_debug_snapshot!(parse(
"message Foo {
reserved 1 to max;
option message_set_wire_format = false;
}"
));
assert_debug_snapshot!(parse(
"message Foo {
reserved 1 to max;
option message_set_wire_format = true;
}"
));
}
#[test]
fn options() {
assert_debug_snapshot!(parse("option (ext.foo).bar = true;"));
assert_debug_snapshot!(parse("option ext.(foo.bar) = true;"));
assert_debug_snapshot!(parse("option opt = ident;"));
assert_debug_snapshot!(parse("option opt = 5;"));
assert_debug_snapshot!(parse("option opt = -5;"));
assert_debug_snapshot!(parse("option opt = 1.1;"));
assert_debug_snapshot!(parse("option opt = 'foo';"));
assert_debug_snapshot!(parse("option opt = { foo: 1 };"));
assert_eq!(
parse("option opt = -ident;"),
Err(vec![NegativeIdentOutsideDefault { span: 13..19 }]),
);
assert_eq!(
parse("option opt = -13835058055282163711;"),
Err(vec![IntegerValueOutOfRange {
expected: "a 64-bit integer".to_owned(),
actual: "-13835058055282163711".to_string(),
span: 13..34,
min: "-9223372036854775808".to_owned(),
max: "18446744073709551615".to_owned(),
}]),
);
}