mirror of
https://github.com/FuelLabs/sway.git
synced 2025-08-16 00:20:36 +00:00

## Description Ran on test branch & working as intended. Only beginning of file `//!` is collected as `DocComment` with `DocStyle::Inner` which is only collected at the `Module` parsing stage. This ensures that any `//!` found after the module docs will be treated as normal comments for now. Ref #4112 for tracking further progress in allowing inner doc comments for `Item`. ## Checklist - [x] I have linked to any relevant issues. Closes #4097 - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers.
1444 lines
26 KiB
Rust
1444 lines
26 KiB
Rust
use std::sync::Arc;
|
|
use swayfmt::{config::user_def::FieldAlignment, Formatter};
|
|
|
|
#[macro_use]
|
|
mod macros;
|
|
|
|
/// Takes a configured formatter as input and formats a given input and checks the actual output against an
|
|
/// expected output. There are two format passes to ensure that the received output does not change on a second pass.
|
|
fn check_with_formatter(unformatted: &str, expected: &str, formatter: &mut Formatter) {
|
|
let first_formatted = Formatter::format(formatter, Arc::from(unformatted), None).unwrap();
|
|
assert_eq_pretty!(first_formatted, expected);
|
|
|
|
let second_formatted =
|
|
Formatter::format(formatter, Arc::from(first_formatted.clone()), None).unwrap();
|
|
assert_eq_pretty!(second_formatted, first_formatted);
|
|
}
|
|
|
|
/// Formats a given input and checks the actual output against an expected
|
|
/// output by calling check_with_formatter() with a default Formatter as input.
|
|
fn check(unformatted: &str, expected: &str) {
|
|
let mut formatter = Formatter::default();
|
|
check_with_formatter(unformatted, expected, &mut formatter);
|
|
}
|
|
|
|
#[test]
|
|
fn const_spacing() {
|
|
check(
|
|
r#"contract;
|
|
pub const TEST:u16=10;
|
|
"#,
|
|
r#"contract;
|
|
pub const TEST: u16 = 10;
|
|
"#,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn struct_alignment() {
|
|
let mut formatter = Formatter::default();
|
|
formatter.config.structures.field_alignment = FieldAlignment::AlignFields(40);
|
|
|
|
check_with_formatter(
|
|
r#"contract;
|
|
pub struct Foo<T, P> {
|
|
barbazfoo: u64,
|
|
baz : bool,
|
|
}
|
|
"#,
|
|
r#"contract;
|
|
pub struct Foo<T, P> {
|
|
barbazfoo : u64,
|
|
baz : bool,
|
|
}
|
|
"#,
|
|
&mut formatter,
|
|
);
|
|
}
|
|
#[test]
|
|
fn struct_ending_comma() {
|
|
check(
|
|
r#"contract;
|
|
pub struct Foo {
|
|
bar: u64,
|
|
baz: bool
|
|
}
|
|
"#,
|
|
r#"contract;
|
|
pub struct Foo {
|
|
bar: u64,
|
|
baz: bool,
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn enum_without_variant_alignment() {
|
|
check(
|
|
r#"contract;
|
|
|
|
enum Color {
|
|
Blue: (), Green: (),
|
|
Red: (),
|
|
Silver: (),
|
|
Grey: () }
|
|
"#,
|
|
r#"contract;
|
|
|
|
enum Color {
|
|
Blue: (),
|
|
Green: (),
|
|
Red: (),
|
|
Silver: (),
|
|
Grey: (),
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn enum_with_variant_alignment() {
|
|
// Creating a config with enum_variant_align_threshold that exceeds longest variant length
|
|
let mut formatter = Formatter::default();
|
|
formatter.config.structures.field_alignment = FieldAlignment::AlignFields(20);
|
|
check_with_formatter(
|
|
r#"contract;
|
|
|
|
enum Color {
|
|
Blue: (), Green: (),
|
|
Red: (),
|
|
Silver: (),
|
|
Grey: (), }
|
|
"#,
|
|
r#"contract;
|
|
|
|
enum Color {
|
|
Blue : (),
|
|
Green : (),
|
|
Red : (),
|
|
Silver : (),
|
|
Grey : (),
|
|
}
|
|
"#,
|
|
&mut formatter,
|
|
);
|
|
}
|
|
#[test]
|
|
fn item_abi_with_generics_and_attributes() {
|
|
check(
|
|
r#"contract;
|
|
|
|
abi StorageMapExample {
|
|
#[storage(write)]fn insert_into_map1(key: u64, value: u64);
|
|
|
|
fn hello(key: u64, value: u64);
|
|
}"#,
|
|
r#"contract;
|
|
|
|
abi StorageMapExample {
|
|
#[storage(write)]
|
|
fn insert_into_map1(key: u64, value: u64);
|
|
|
|
fn hello(key: u64, value: u64);
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn multi_items() {
|
|
check(
|
|
r#"contract;
|
|
|
|
pub const TEST: u16 = 10;
|
|
pub const TEST1: u16 = 10;"#,
|
|
r#"contract;
|
|
|
|
pub const TEST: u16 = 10;
|
|
pub const TEST1: u16 = 10;
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn ty_formatting() {
|
|
check(
|
|
r#"contract;
|
|
|
|
enum TestTy {
|
|
Infer:
|
|
_,
|
|
Array : [u8;
|
|
40],
|
|
String: str[
|
|
4
|
|
],
|
|
PathType : root::
|
|
example::
|
|
type,
|
|
TupleNil: (),
|
|
Tuple: ( u64,
|
|
u32
|
|
),
|
|
}"#,
|
|
r#"contract;
|
|
|
|
enum TestTy {
|
|
Infer: _,
|
|
Array: [u8; 40],
|
|
String: str[4],
|
|
PathType: root::example::type,
|
|
TupleNil: (),
|
|
Tuple: (u64, u32),
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn storage_without_alignment() {
|
|
check(
|
|
r#"contract;
|
|
|
|
struct Type1 {
|
|
foo: u64,
|
|
}
|
|
|
|
struct Type2 {
|
|
bar: u64,
|
|
}
|
|
|
|
storage {
|
|
var1: Type1=Type1{ foo: 8 },
|
|
var2: Type2=Type2{ bar: 9 },
|
|
}
|
|
"#,
|
|
r#"contract;
|
|
|
|
struct Type1 {
|
|
foo: u64,
|
|
}
|
|
|
|
struct Type2 {
|
|
bar: u64,
|
|
}
|
|
|
|
storage {
|
|
var1: Type1 = Type1 { foo: 8 },
|
|
var2: Type2 = Type2 { bar: 9 },
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn storage_with_alignment() {
|
|
let mut formatter = Formatter::default();
|
|
formatter.config.structures.field_alignment = FieldAlignment::AlignFields(50);
|
|
check_with_formatter(
|
|
r#"contract;
|
|
|
|
struct Type1 {
|
|
foo: u64,
|
|
}
|
|
|
|
struct Type2 {
|
|
bar: u64,
|
|
}
|
|
|
|
storage {
|
|
long_var_name: Type1=Type1{ foo: 8 },
|
|
var2: Type2=Type2{ bar: 9 },
|
|
}
|
|
"#,
|
|
r#"contract;
|
|
|
|
struct Type1 {
|
|
foo : u64,
|
|
}
|
|
|
|
struct Type2 {
|
|
bar : u64,
|
|
}
|
|
|
|
storage {
|
|
long_var_name : Type1 = Type1 { foo: 8 },
|
|
var2 : Type2 = Type2 { bar: 9 },
|
|
}
|
|
"#,
|
|
&mut formatter,
|
|
);
|
|
}
|
|
#[test]
|
|
fn storage_initializer() {
|
|
check(
|
|
r#"contract;
|
|
|
|
struct Type1 {
|
|
x: u64,
|
|
y: u64,
|
|
}
|
|
|
|
struct Type2 {
|
|
w: b256,
|
|
z: bool,
|
|
}
|
|
|
|
storage {
|
|
var1: Type1 = Type1 {
|
|
|
|
x: 0,
|
|
|
|
y:
|
|
0,
|
|
},
|
|
var2: Type2 = Type2 { w: 0x0000000000000000000000000000000000000000000000000000000000000000,z: false,
|
|
},
|
|
}"#,
|
|
r#"contract;
|
|
|
|
struct Type1 {
|
|
x: u64,
|
|
y: u64,
|
|
}
|
|
|
|
struct Type2 {
|
|
w: b256,
|
|
z: bool,
|
|
}
|
|
|
|
storage {
|
|
var1: Type1 = Type1 { x: 0, y: 0 },
|
|
var2: Type2 = Type2 {
|
|
w: 0x0000000000000000000000000000000000000000000000000000000000000000,
|
|
z: false,
|
|
},
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn item_fn() {
|
|
check(
|
|
r#"contract;
|
|
|
|
pub fn hello( person: String ) -> String {let greeting = 42;greeting.to_string()}
|
|
fn goodbye() -> usize {let farewell: usize = 5; farewell }"#,
|
|
r#"contract;
|
|
|
|
pub fn hello(person: String) -> String {
|
|
let greeting = 42;
|
|
greeting.to_string()
|
|
}
|
|
fn goodbye() -> usize {
|
|
let farewell: usize = 5;
|
|
farewell
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn same_line_where() {
|
|
check(
|
|
r#"contract;
|
|
|
|
pub fn hello( person: String ) -> String where T: Eq,{let greeting = 42;greeting.to_string()}"#,
|
|
r#"contract;
|
|
|
|
pub fn hello(person: String) -> String
|
|
where
|
|
T: Eq,
|
|
{
|
|
let greeting = 42;
|
|
greeting.to_string()
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn trait_and_super_trait() {
|
|
check(
|
|
r#"library traits;
|
|
|
|
trait Person{ fn name( self )->String;fn age( self )->usize; }
|
|
trait Student:Person {fn university(self) -> String;}
|
|
trait Programmer {fn fav_language(self) -> String;}
|
|
trait CompSciStudent: Programmer+Student {fn git_username(self) -> String;}
|
|
trait TraitWithGenerics<T> where T: String {fn from(b: T) -> Self;}"#,
|
|
r#"library traits;
|
|
|
|
trait Person {
|
|
fn name(self) -> String;
|
|
fn age(self) -> usize;
|
|
}
|
|
trait Student: Person {
|
|
fn university(self) -> String;
|
|
}
|
|
trait Programmer {
|
|
fn fav_language(self) -> String;
|
|
}
|
|
trait CompSciStudent: Programmer + Student {
|
|
fn git_username(self) -> String;
|
|
}
|
|
trait TraitWithGenerics<T>
|
|
where
|
|
T: String
|
|
{
|
|
fn from(b: T) -> Self;
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn method_calls() {
|
|
let mut formatter = Formatter::default();
|
|
formatter.config.structures.small_structures_single_line = true;
|
|
formatter.config.whitespace.max_width = 220;
|
|
check_with_formatter(
|
|
r#"script;
|
|
|
|
struct Opts {
|
|
gas: u64,
|
|
coins: u64,
|
|
id: ContractId,
|
|
}
|
|
|
|
fn main( ) -> bool{
|
|
let default_gas = 1_000_000_000_000 ;let fuelcoin_id = ContractId::from(0x018f59fe434b323a5054e7bb41de983f4926a3c5d3e4e1f9f33b5f0f0e611889);
|
|
|
|
let balance_test_id = ContractId :: from( 0x597e5ddb1a6bec92a96a73e4f0bc6f6e3e7b21f5e03e1c812cd63cffac480463 ) ;
|
|
|
|
let fuel_coin = abi( TestFuelCoin, fuelcoin_id.into( ) ) ;
|
|
|
|
assert(fuelcoin_balance == 0);
|
|
|
|
fuel_coin.mint {
|
|
gas: default_gas
|
|
}
|
|
|
|
(11);
|
|
|
|
fuelcoin_balance = balance_of(fuelcoin_id, fuelcoin_id);
|
|
assert( fuelcoin_balance == 11 ) ;
|
|
|
|
fuel_coin.burn {
|
|
gas: default_gas
|
|
}
|
|
(7);
|
|
|
|
fuelcoin_balance = balance_of(fuelcoin_id, fuelcoin_id);
|
|
assert(fuelcoin_balance == 4);
|
|
|
|
fuel_coin.force_transfer {
|
|
gas: default_gas
|
|
}
|
|
(3, fuelcoin_id, balance_test_id);
|
|
|
|
fuelcoin_balance = balance_of(fuelcoin_id, fuelcoin_id);
|
|
let balance_test_contract_balance = balance_of(fuelcoin_id, balance_test_id);
|
|
assert(fuelcoin_balance == 1);
|
|
assert(balance_test_contract_balance == 3);
|
|
|
|
true
|
|
}"#,
|
|
r#"script;
|
|
|
|
struct Opts {
|
|
gas: u64,
|
|
coins: u64,
|
|
id: ContractId,
|
|
}
|
|
|
|
fn main() -> bool {
|
|
let default_gas = 1_000_000_000_000;
|
|
let fuelcoin_id = ContractId::from(0x018f59fe434b323a5054e7bb41de983f4926a3c5d3e4e1f9f33b5f0f0e611889);
|
|
|
|
let balance_test_id = ContractId::from(0x597e5ddb1a6bec92a96a73e4f0bc6f6e3e7b21f5e03e1c812cd63cffac480463);
|
|
|
|
let fuel_coin = abi(TestFuelCoin, fuelcoin_id.into());
|
|
|
|
assert(fuelcoin_balance == 0);
|
|
|
|
fuel_coin.mint { gas: default_gas }(11);
|
|
|
|
fuelcoin_balance = balance_of(fuelcoin_id, fuelcoin_id);
|
|
assert(fuelcoin_balance == 11);
|
|
|
|
fuel_coin.burn { gas: default_gas }(7);
|
|
|
|
fuelcoin_balance = balance_of(fuelcoin_id, fuelcoin_id);
|
|
assert(fuelcoin_balance == 4);
|
|
|
|
fuel_coin.force_transfer { gas: default_gas }(3, fuelcoin_id, balance_test_id);
|
|
|
|
fuelcoin_balance = balance_of(fuelcoin_id, fuelcoin_id);
|
|
let balance_test_contract_balance = balance_of(fuelcoin_id, balance_test_id);
|
|
assert(fuelcoin_balance == 1);
|
|
assert(balance_test_contract_balance == 3);
|
|
|
|
true
|
|
}
|
|
"#,
|
|
&mut formatter,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn struct_comments() {
|
|
check(
|
|
r#"contract;
|
|
// This is a comment, for this one to be placed correctly we need to have Module visitor implemented
|
|
pub struct Foo { // Here is a comment
|
|
|
|
|
|
|
|
// Trying some ASCII art
|
|
baz:u64,
|
|
|
|
|
|
|
|
|
|
bazzz:u64
|
|
|
|
// ________ ___ ___ _______ ___ ___ ________ ________ ________
|
|
// |\ _____\\ \|\ \|\ ___ \ |\ \ |\ \ |\ __ \|\ __ \|\ ____\
|
|
// \ \ \__/\ \ \\\ \ \ __/|\ \ \ \ \ \ \ \ \|\ \ \ \|\ /\ \ \___|_
|
|
// \ \ __\\ \ \\\ \ \ \_|/_\ \ \ \ \ \ \ \ __ \ \ __ \ \_____ \
|
|
// \ \ \_| \ \ \\\ \ \ \_|\ \ \ \____ \ \ \____\ \ \ \ \ \ \|\ \|____|\ \
|
|
// \ \__\ \ \_______\ \_______\ \_______\ \ \_______\ \__\ \__\ \_______\____\_\ \
|
|
// \|__| \|_______|\|_______|\|_______| \|_______|\|__|\|__|\|_______|\_________\
|
|
// \|_________|
|
|
}
|
|
// This is a comment
|
|
"#,
|
|
r#"contract;
|
|
// This is a comment, for this one to be placed correctly we need to have Module visitor implemented
|
|
pub struct Foo { // Here is a comment
|
|
// Trying some ASCII art
|
|
baz: u64,
|
|
bazzz: u64,
|
|
// ________ ___ ___ _______ ___ ___ ________ ________ ________
|
|
// |\ _____\\ \|\ \|\ ___ \ |\ \ |\ \ |\ __ \|\ __ \|\ ____\
|
|
// \ \ \__/\ \ \\\ \ \ __/|\ \ \ \ \ \ \ \ \|\ \ \ \|\ /\ \ \___|_
|
|
// \ \ __\\ \ \\\ \ \ \_|/_\ \ \ \ \ \ \ \ __ \ \ __ \ \_____ \
|
|
// \ \ \_| \ \ \\\ \ \ \_|\ \ \ \____ \ \ \____\ \ \ \ \ \ \|\ \|____|\ \
|
|
// \ \__\ \ \_______\ \_______\ \_______\ \ \_______\ \__\ \__\ \_______\____\_\ \
|
|
// \|__| \|_______|\|_______|\|_______| \|_______|\|__|\|__|\|_______|\_________\
|
|
// \|_________|
|
|
}
|
|
// This is a comment
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn comments_empty_struct() {
|
|
check(
|
|
r#"contract;
|
|
|
|
struct AlignMyComments {
|
|
// Align here please
|
|
// Overindented comment
|
|
// Underindented comment
|
|
}"#,
|
|
r#"contract;
|
|
|
|
struct AlignMyComments {
|
|
// Align here please
|
|
// Overindented comment
|
|
// Underindented comment
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn comments_empty_traits() {
|
|
check(
|
|
r#"contract;
|
|
|
|
trait AlignMyComments {
|
|
// Align here please
|
|
// Overindented comment
|
|
// Underindented comment
|
|
}"#,
|
|
r#"contract;
|
|
|
|
trait AlignMyComments {
|
|
// Align here please
|
|
// Overindented comment
|
|
// Underindented comment
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn comments_empty_fns() {
|
|
check(
|
|
r#"contract;
|
|
|
|
fn single_comment_same_line() { /* a comment */ }
|
|
|
|
fn single_comment() -> bool {
|
|
// TODO: This is a TODO
|
|
}
|
|
|
|
fn multiline_comments() {
|
|
// Multi
|
|
// line
|
|
// comment
|
|
}"#,
|
|
r#"contract;
|
|
|
|
fn single_comment_same_line() {
|
|
/* a comment */
|
|
}
|
|
|
|
fn single_comment() -> bool {
|
|
// TODO: This is a TODO
|
|
}
|
|
|
|
fn multiline_comments() {
|
|
// Multi
|
|
// line
|
|
// comment
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn enum_comments() {
|
|
check(
|
|
r#"contract;
|
|
pub enum Bazz { // Here is a comment
|
|
// Trying some ASCII art
|
|
baz: (),
|
|
|
|
|
|
|
|
|
|
|
|
bazzz: (),//-----
|
|
//--D--
|
|
//-----
|
|
}
|
|
"#,
|
|
r#"contract;
|
|
pub enum Bazz { // Here is a comment
|
|
// Trying some ASCII art
|
|
baz: (),
|
|
bazzz: (),//-----
|
|
//--D--
|
|
//-----
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn fn_comments() {
|
|
check(
|
|
r#"contract;
|
|
// This is a comment before a fn
|
|
// This is another comment before a fn
|
|
fn hello_world( baz: /* this is a comment */ u64) { let x = 5; // This is a comment inside the block
|
|
}
|
|
"#,
|
|
r#"contract;
|
|
// This is a comment before a fn
|
|
// This is another comment before a fn
|
|
fn hello_world(baz: /* this is a comment */ u64) {
|
|
let x = 5; // This is a comment inside the block
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn abi_comments() {
|
|
check(
|
|
r#"contract;
|
|
|
|
// This is an abi
|
|
abi StorageMapExample {
|
|
// insert_into_map is blah blah
|
|
#[storage(write)] // this is some other comment
|
|
fn insert_into_map(key: u64, value: u64);
|
|
// this is the last comment inside the StorageMapExample
|
|
}"#,
|
|
r#"contract;
|
|
|
|
// This is an abi
|
|
abi StorageMapExample {
|
|
// insert_into_map is blah blah
|
|
#[storage(write)] // this is some other comment
|
|
fn insert_into_map(key: u64, value: u64);
|
|
// this is the last comment inside the StorageMapExample
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn const_comments() {
|
|
check(
|
|
r#"contract;
|
|
pub const /* TEST: blah blah tests */ TEST: u16 = 10; // This is a comment next to a const"#,
|
|
r#"contract;
|
|
pub const /* TEST: blah blah tests */ TEST: u16 = 10; // This is a comment next to a const
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn storage_comments() {
|
|
check(
|
|
r#"contract;
|
|
|
|
struct Type1 {
|
|
foo: u64,
|
|
}
|
|
struct Type2 {
|
|
bar: u64,
|
|
}
|
|
storage {
|
|
// Testing a comment inside storage
|
|
long_var_name: Type1=Type1{ foo: 8},
|
|
// Testing another comment
|
|
var2: Type2 = Type2{bar:9} // This is the last comment
|
|
}"#,
|
|
r#"contract;
|
|
|
|
struct Type1 {
|
|
foo: u64,
|
|
}
|
|
struct Type2 {
|
|
bar: u64,
|
|
}
|
|
storage {
|
|
// Testing a comment inside storage
|
|
long_var_name: Type1 = Type1 { foo: 8 },
|
|
// Testing another comment
|
|
var2: Type2 = Type2 { bar: 9 }, // This is the last comment
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn trait_comments() {
|
|
check(
|
|
r#"contract;
|
|
// This is the programmer trait
|
|
trait Programmer {
|
|
// Returns fav languages of this Programmer.
|
|
fn fav_language(self) -> String;
|
|
}"#,
|
|
r#"contract;
|
|
// This is the programmer trait
|
|
trait Programmer {
|
|
// Returns fav languages of this Programmer.
|
|
fn fav_language(self) -> String;
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn where_comment() {
|
|
check(
|
|
r#"contract;
|
|
|
|
pub fn hello( person: String ) -> String where /* This is next to where */ T: Eq, /*Here is a comment*/{let greeting = 42;greeting.to_string()}"#,
|
|
r#"contract;
|
|
|
|
pub fn hello(person: String) -> String
|
|
where /* This is next to where */
|
|
T: Eq, /*Here is a comment*/
|
|
{
|
|
let greeting = 42;
|
|
greeting.to_string()
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn impl_spacing() {
|
|
check(
|
|
r#"script;
|
|
|
|
struct Foo {
|
|
bar: u64,
|
|
baz: bool,
|
|
}
|
|
|
|
trait Qux {
|
|
fn is_baz_true(self) -> bool;
|
|
}
|
|
|
|
impl<A , B> Qux<A, B> for
|
|
Foo
|
|
where
|
|
A : Qux,
|
|
B: Qux ,
|
|
{fn is_baz_true(self) -> bool {
|
|
self.baz
|
|
}}"#,
|
|
r#"script;
|
|
|
|
struct Foo {
|
|
bar: u64,
|
|
baz: bool,
|
|
}
|
|
|
|
trait Qux {
|
|
fn is_baz_true(self) -> bool;
|
|
}
|
|
|
|
impl<A, B> Qux<A, B> for Foo where
|
|
A: Qux,
|
|
B: Qux,
|
|
{
|
|
fn is_baz_true(self) -> bool {
|
|
self.baz
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn impl_without_generics() {
|
|
check(
|
|
r#"script;
|
|
|
|
struct Foo {
|
|
bar: u64,
|
|
baz: bool,
|
|
}
|
|
|
|
trait Qux {
|
|
fn is_baz_true(self) -> bool;
|
|
}
|
|
|
|
impl Qux for
|
|
Foo
|
|
{fn is_baz_true(self) -> bool {
|
|
self.baz
|
|
}}"#,
|
|
r#"script;
|
|
|
|
struct Foo {
|
|
bar: u64,
|
|
baz: bool,
|
|
}
|
|
|
|
trait Qux {
|
|
fn is_baz_true(self) -> bool;
|
|
}
|
|
|
|
impl Qux for Foo {
|
|
fn is_baz_true(self) -> bool {
|
|
self.baz
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn newline_sequence_formatting() {
|
|
check(
|
|
r#"script;
|
|
|
|
fn main() {
|
|
let number: u64 = 10;
|
|
|
|
let number2: u64 = 20;
|
|
|
|
|
|
|
|
let number3: u64 = 30;
|
|
|
|
|
|
|
|
}"#,
|
|
r#"script;
|
|
|
|
fn main() {
|
|
let number: u64 = 10;
|
|
|
|
let number2: u64 = 20;
|
|
|
|
let number3: u64 = 30;
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn inner_doc_comments() {
|
|
check(
|
|
r#"script;
|
|
|
|
enum Color {
|
|
//! Color is a Sway enum
|
|
blue: (),
|
|
red: ()
|
|
}
|
|
|
|
fn main() {
|
|
}"#,
|
|
r#"script;
|
|
|
|
enum Color {
|
|
//! Color is a Sway enum
|
|
blue: (),
|
|
red: (),
|
|
}
|
|
|
|
fn main() {}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn outer_doc_comments() {
|
|
check(
|
|
r#"script;
|
|
|
|
enum Color {
|
|
/// Blue color
|
|
blue: (),
|
|
/// Red color
|
|
red: ()
|
|
}
|
|
/// This is the main function
|
|
fn main() {
|
|
}"#,
|
|
r#"script;
|
|
|
|
enum Color {
|
|
/// Blue color
|
|
blue: (),
|
|
/// Red color
|
|
red: (),
|
|
}
|
|
/// This is the main function
|
|
fn main() {}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn newline_comment_handler_interaction() {
|
|
check(
|
|
r#"script;
|
|
|
|
// use statements
|
|
use std::*;
|
|
|
|
fn main() {
|
|
// Array of integers with type ascription
|
|
let array_of_integers: [u8;
|
|
5] = [1, 2, 3, 4, 5];
|
|
|
|
|
|
// Array of strings
|
|
let array_of_strings = [ "Bob", "Jan", "Ron"];
|
|
}
|
|
"#,
|
|
r#"script;
|
|
|
|
// use statements
|
|
use std::*;
|
|
|
|
fn main() {
|
|
// Array of integers with type ascription
|
|
let array_of_integers: [u8; 5] = [1, 2, 3, 4, 5];
|
|
|
|
// Array of strings
|
|
let array_of_strings = ["Bob", "Jan", "Ron"];
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn comments_before_module_kind() {
|
|
check(
|
|
r#"// something about module kind
|
|
// something else about module kind
|
|
library test_module_kind_with_comments;"#,
|
|
r#"// something about module kind
|
|
// something else about module kind
|
|
library test_module_kind_with_comments;
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn newline_before_comments() {
|
|
check(
|
|
r#"
|
|
|
|
|
|
// something about module kind
|
|
// something else about module kind
|
|
library test_module_kind_with_comments;"#,
|
|
r#"// something about module kind
|
|
// something else about module kind
|
|
library test_module_kind_with_comments;
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn destructure_structs() {
|
|
check(
|
|
r#"library test_destructure_structs;
|
|
|
|
struct Point {
|
|
x: u64,
|
|
y: u64,
|
|
}
|
|
struct TupleInStruct {
|
|
nested_tuple: (u64, (u32, (bool, str[2]))),
|
|
}
|
|
fn struct_destructuring() {
|
|
let point1 = Point { x: 0, y: 0 };
|
|
let Point{x, y} = point1;
|
|
let point2 = Point { x: 18446744073709551615, y: 18446744073709551615};
|
|
let Point{extremely_long_var_name, other_really_long_var_name} = point2;
|
|
let tuple_in_struct = TupleInStruct {
|
|
nested_tuple: (
|
|
42u64,
|
|
(42u32, (true, "ok"))
|
|
),
|
|
};
|
|
let TupleInStruct {
|
|
nested_tuple: (a, (b, (c, d))),
|
|
} = tuple_in_struct;
|
|
}
|
|
"#,
|
|
r#"library test_destructure_structs;
|
|
|
|
struct Point {
|
|
x: u64,
|
|
y: u64,
|
|
}
|
|
struct TupleInStruct {
|
|
nested_tuple: (u64, (u32, (bool, str[2]))),
|
|
}
|
|
fn struct_destructuring() {
|
|
let point1 = Point { x: 0, y: 0 };
|
|
let Point { x, y } = point1;
|
|
let point2 = Point {
|
|
x: 18446744073709551615,
|
|
y: 18446744073709551615,
|
|
};
|
|
let Point {
|
|
extremely_long_var_name,
|
|
other_really_long_var_name,
|
|
} = point2;
|
|
let tuple_in_struct = TupleInStruct {
|
|
nested_tuple: (42u64, (42u32, (true, "ok"))),
|
|
};
|
|
let TupleInStruct {
|
|
nested_tuple: (a, (b, (c, d))),
|
|
} = tuple_in_struct;
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn multiline_collections() {
|
|
check(
|
|
r#"library test_multiline_collections;
|
|
fn func_with_multiline_collections() {
|
|
let x = (
|
|
"hello",
|
|
"world",
|
|
);
|
|
}
|
|
"#,
|
|
r#"library test_multiline_collections;
|
|
fn func_with_multiline_collections() {
|
|
let x = ("hello", "world");
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn comments_between_if_else() {
|
|
check(
|
|
r#"script;
|
|
|
|
fn main() {
|
|
if pledge_history_index != 0 {
|
|
// This is a comment
|
|
storage.pledge_history.insert((user, pledge_history_index), pledge);
|
|
}
|
|
// This is also a comment,
|
|
// but multiline
|
|
else if true {
|
|
// This is yet another comment
|
|
storage.pledge_count.insert(user, pledge_count + 1);
|
|
}
|
|
// This is the last comment
|
|
else {
|
|
storage.pledge_count.insert(user, pledge_count + 1);
|
|
}
|
|
}
|
|
"#,
|
|
r#"script;
|
|
|
|
fn main() {
|
|
if pledge_history_index != 0 {
|
|
// This is a comment
|
|
storage.pledge_history.insert((user, pledge_history_index), pledge);
|
|
}
|
|
// This is also a comment,
|
|
// but multiline
|
|
else if true {
|
|
// This is yet another comment
|
|
storage.pledge_count.insert(user, pledge_count + 1);
|
|
}
|
|
// This is the last comment
|
|
else {
|
|
storage.pledge_count.insert(user, pledge_count + 1);
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
#[test]
|
|
fn parameterless_attributes() {
|
|
check(
|
|
r#"library my_lib;
|
|
|
|
abi MyContract {
|
|
#[test]
|
|
fn foo();
|
|
}
|
|
"#,
|
|
r#"library my_lib;
|
|
|
|
abi MyContract {
|
|
#[test]
|
|
fn foo();
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn traits_with_def_block() {
|
|
check(
|
|
r#"script;
|
|
|
|
pub trait Foo {
|
|
fn foo(self, other: Self);
|
|
} {
|
|
fn bar(self, other: Self) {}
|
|
}
|
|
|
|
fn main() {}
|
|
"#,
|
|
r#"script;
|
|
|
|
pub trait Foo {
|
|
fn foo(self, other: Self);
|
|
} {
|
|
fn bar(self, other: Self) {}
|
|
}
|
|
|
|
fn main() {}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn if_else_multiline_to_inline() {
|
|
check(
|
|
r#"script;
|
|
|
|
fn main() {
|
|
if foo {
|
|
let x = 1;
|
|
} else {
|
|
bar(y) ;
|
|
}
|
|
}
|
|
"#,
|
|
r#"script;
|
|
|
|
fn main() {
|
|
if foo { let x = 1; } else { bar(y); }
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn if_else_retain_multiline() {
|
|
check(
|
|
r#"script;
|
|
|
|
|
|
fn main() {
|
|
if foo {
|
|
let really_long_variable = 1;
|
|
} else {
|
|
bar(y) ;
|
|
}
|
|
}
|
|
"#,
|
|
r#"script;
|
|
|
|
fn main() {
|
|
if foo {
|
|
let really_long_variable = 1;
|
|
} else {
|
|
bar(y);
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn multiple_comma_separated_attributes() {
|
|
check(
|
|
r#"library my_lib;
|
|
|
|
#[test, inline(always), storage(read, write), payable]
|
|
fn foo() {}
|
|
"#,
|
|
r#"library my_lib;
|
|
|
|
#[test, inline(always), storage(read, write), payable]
|
|
fn foo() {}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn stack_of_comma_separated_attributes1() {
|
|
check(
|
|
r#"library my_lib;
|
|
|
|
/// this is a doc comment
|
|
#[storage(read, write), payable]
|
|
#[test, inline(always)]
|
|
fn foo() {}
|
|
"#,
|
|
r#"library my_lib;
|
|
|
|
/// this is a doc comment
|
|
#[storage(read, write), payable]
|
|
#[test, inline(always)]
|
|
fn foo() {}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn stack_of_comma_separated_attributes2() {
|
|
check(
|
|
r#"library my_lib;
|
|
|
|
/// this is a doc comment
|
|
#[storage(read, write)]
|
|
#[payable]
|
|
#[test]
|
|
#[inline(always)]
|
|
fn foo() {}
|
|
"#,
|
|
r#"library my_lib;
|
|
|
|
/// this is a doc comment
|
|
#[storage(read, write)]
|
|
#[payable]
|
|
#[test]
|
|
#[inline(always)]
|
|
fn foo() {}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn comment_between_closing_brace_and_else() {
|
|
check(
|
|
r#"contract;
|
|
|
|
impl MyContract for Contract {
|
|
fn is_blue() -> bool {
|
|
if self == PrimaryColor::Blue {
|
|
true
|
|
}
|
|
// Overindented comment, underindented else
|
|
else if self == PrimaryColor::Red {
|
|
true
|
|
} // Trailing multiline comment should be newlined
|
|
// Underindented comment
|
|
// Overindented else
|
|
else {
|
|
false
|
|
}
|
|
}
|
|
}"#,
|
|
r#"contract;
|
|
|
|
impl MyContract for Contract {
|
|
fn is_blue() -> bool {
|
|
if self == PrimaryColor::Blue {
|
|
true
|
|
}
|
|
// Overindented comment, underindented else
|
|
else if self == PrimaryColor::Red {
|
|
true
|
|
}
|
|
// Trailing multiline comment should be newlined
|
|
// Underindented comment
|
|
// Overindented else
|
|
else {
|
|
false
|
|
}
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn comment_between_if_else_inline_to_multiline() {
|
|
check(
|
|
r#"contract;
|
|
|
|
impl MyContract for Contract {
|
|
fn is_blue() -> bool {
|
|
if self == PrimaryColor::Blue { true }
|
|
// TODO remove this else when exhaustive ifs are checked for
|
|
else { false }
|
|
}
|
|
}"#,
|
|
r#"contract;
|
|
|
|
impl MyContract for Contract {
|
|
fn is_blue() -> bool {
|
|
if self == PrimaryColor::Blue {
|
|
true
|
|
}
|
|
// TODO remove this else when exhaustive ifs are checked for
|
|
else {
|
|
false
|
|
}
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn asm_block() {
|
|
check(
|
|
r#"library my_lib;
|
|
|
|
fn foo() {
|
|
asm(r1: self, r2: other, r3, r4) {
|
|
addi r3 zero i32;
|
|
meq r4 r1 r2 r3;
|
|
r4: bool
|
|
}
|
|
}
|
|
"#,
|
|
r#"library my_lib;
|
|
|
|
fn foo() {
|
|
asm(r1: self, r2: other, r3, r4) {
|
|
addi r3 zero i32;
|
|
meq r4 r1 r2 r3;
|
|
r4: bool
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn empty_blocks() {
|
|
check(
|
|
r#"contract;
|
|
|
|
fn contents() {
|
|
let i = { };
|
|
match i {
|
|
}
|
|
if true { }
|
|
}
|
|
fn empty() {}
|
|
"#,
|
|
r#"contract;
|
|
|
|
fn contents() {
|
|
let i = {};
|
|
match i {}
|
|
if true {}
|
|
}
|
|
fn empty() {}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn abi_supertrait() {
|
|
check(
|
|
r#"contract;
|
|
|
|
trait ABIsupertrait {
|
|
fn foo();
|
|
}
|
|
|
|
abi MyAbi : ABIsupertrait {
|
|
fn bar();
|
|
} {
|
|
fn baz() {
|
|
Self::foo() // supertrait method usage
|
|
}
|
|
}
|
|
|
|
impl ABIsupertrait for Contract {
|
|
fn foo() {}
|
|
}
|
|
|
|
// The implementation of MyAbi for Contract must also implement ABIsupertrait
|
|
impl MyAbi for Contract {
|
|
fn bar() {
|
|
Self::foo() // supertrait method usage
|
|
}
|
|
}
|
|
"#,
|
|
r#"contract;
|
|
|
|
trait ABIsupertrait {
|
|
fn foo();
|
|
}
|
|
|
|
abi MyAbi : ABIsupertrait {
|
|
fn bar();
|
|
} {
|
|
fn baz() {
|
|
Self::foo() // supertrait method usage
|
|
}
|
|
}
|
|
|
|
impl ABIsupertrait for Contract {
|
|
fn foo() {}
|
|
}
|
|
|
|
// The implementation of MyAbi for Contract must also implement ABIsupertrait
|
|
impl MyAbi for Contract {
|
|
fn bar() {
|
|
Self::foo() // supertrait method usage
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|