// Copyright (c) ZeroC, Inc. mod test_helpers; mod typealias { use crate::test_helpers::*; use slicec::diagnostics::{Diagnostic, Error}; use slicec::grammar::*; use slicec::slice_file::Span; use test_case::test_case; #[test_case("struct S {}", "S", "Slice2"; "structs")] #[test_case("class C {}", "C", "Slice1"; "classes")] #[test_case("enum E { Foo }", "E", "Slice1"; "enums")] #[test_case("custom C", "C", "Slice2"; "custom types")] #[test_case("", "bool", "Slice2"; "primitives")] #[test_case("", "Sequence", "Slice2"; "sequences")] #[test_case("", "Dictionary", "Slice2"; "dictionaries")] #[test_case("typealias T = bool", "T", "Slice2"; "type aliases")] #[test_case("", "Result", "Slice2"; "result types")] fn can_have_type_alias_of(definition: &str, identifier: &str, mode: &str) { // Arrange let slice = format!( " mode = {mode} module Test {definition} typealias Alias = {identifier} " ); // Act let ast = parse_for_ast(slice); // Assert let type_alias = ast.find_element::("Test::Alias").unwrap(); type_alias.underlying.definition(); // Panics if the type-alias hasn't been initialized correctly. } #[test] fn can_be_used_as_field() { // Arrange let slice = " module Test typealias MyDict = Dictionary> compact struct S { dict: MyDict } "; // Act/Assert assert_parses(slice); } #[test] fn can_be_used_as_parameter() { // Arrange let slice = " module Test typealias MyDict = Dictionary> interface I { op(dict: MyDict) } "; // Act/Assert assert_parses(slice); } #[test] fn is_resolvable() { // Arrange let slice = " module Test typealias MyInt = varuint32 "; // Act let ast = parse_for_ast(slice); // Assert let type_alias = ast.find_element::("Test::MyInt").unwrap(); assert_eq!(type_alias.identifier(), "MyInt"); assert!(matches!( type_alias.underlying.concrete_type(), Types::Primitive(Primitive::VarUInt32), )); } #[test] fn is_resolved_as_the_aliased_type_when_used() { // Arrange let slice = " module Test typealias MyInt = varuint32 compact struct S { a: MyInt } "; // Act let ast = parse_for_ast(slice); // Assert let field = ast.find_element::("Test::S::a").unwrap(); assert_eq!(field.identifier(), "a"); assert!(matches!( field.data_type.concrete_type(), Types::Primitive(Primitive::VarUInt32), )); } #[test] fn cannot_be_optional() { // Arrange let slice = " module Test typealias Test = bool? "; // Act let diagnostics = parse_for_diagnostics(slice); // Assert let expected = Diagnostic::new(Error::TypeAliasOfOptional) .set_span(&Span::new((3, 13).into(), (3, 27).into(), "string-0")) .add_note( "try removing the trailing `?` modifier from its definition", Some(&Span::new((3, 30).into(), (3, 35).into(), "string-0")), ) .add_note( "instead of aliasing an optional type directly, try making it optional where you use it", None, ); check_diagnostics(diagnostics, [expected]); } #[test_case("Slice1", "uint32"; "Slice1")] #[test_case("Slice2", "AnyClass"; "Slice2")] fn reject_underlying_types_based_on_mode(mode: &str, underlying_type: &str) { // Arrange let slice = format!( " mode = {mode} module Test typealias Foo = {underlying_type} " ); // Act let diagnostics = parse_for_diagnostics(slice); // Assert let expected = Diagnostic::new(Error::UnsupportedType { kind: underlying_type.to_owned(), mode: match mode { "Slice1" => CompilationMode::Slice1, "Slice2" => CompilationMode::Slice2, _ => panic!(), }, }); check_diagnostics(diagnostics, [expected]); } #[test_case("Slice1", "AnyClass"; "Slice1")] #[test_case("Slice2", "uint32"; "Slice2")] fn allow_underlying_types_based_on_mode(mode: &str, underlying_type: &str) { // Arrange let slice = format!( " mode = {mode} module Test typealias Foo = {underlying_type} " ); // Act let ast = parse_for_ast(slice); // Assert let type_alias = ast.find_element::("Test::Foo").unwrap(); assert_eq!(type_alias.underlying.type_string(), underlying_type); } }