Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix incorrect attributes handling #2493

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
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
37 changes: 34 additions & 3 deletions crates/snforge-scarb-plugin/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use self::{named::NamedArgs, unnamed::UnnamedArgs};
use crate::attributes::{AttributeInfo, ErrorExt};
use crate::attributes::{AttributeInfo, ErrorExt, ValidArgs, ValidArgsTypes, ValidNamedArgs};
use cairo_lang_macro::Diagnostic;
use cairo_lang_syntax::node::{
ast::{ArgClause, Expr, OptionArgListParenthesized},
Expand Down Expand Up @@ -67,17 +67,48 @@ impl Arguments {
}

#[inline]
pub fn named_only<T: AttributeInfo>(&self) -> Result<&NamedArgs, Diagnostic> {
pub fn named_only<T: AttributeInfo + ValidArgs>(&self) -> Result<&NamedArgs, Diagnostic> {
if self.shorthand.is_empty() && self.unnamed.is_empty() {
match T::VALID_ARGS {
ValidArgsTypes::Named(valid_named_args)
| ValidArgsTypes::Both { valid_named_args } => match valid_named_args {
ValidNamedArgs::All => {}
ValidNamedArgs::Restricted(valid_named_args) => {
if let Some(arg) = self
.named
.iter()
.map(|(arg, _)| arg)
.find(|arg| !valid_named_args.contains(&arg.as_str()))
{
return Err(T::error(format!(
"unsupported named argument \"{arg}\" provided",
)));
}
}
},
ValidArgsTypes::Unnamed => panic!(
"`named_only` arguments requested where only `Unnamed` arguments are valid"
),
ValidArgsTypes::None => {
panic!("`named_only` arguments requested where no arguments are valid")
}
}

Ok(&self.named)
} else {
Err(T::error("can be used with named attributes only"))
}
}

#[inline]
pub fn unnamed_only<T: AttributeInfo>(&self) -> Result<UnnamedArgs, Diagnostic> {
pub fn unnamed_only<T: AttributeInfo + ValidArgs>(&self) -> Result<UnnamedArgs, Diagnostic> {
if self.shorthand.is_empty() && self.named.is_empty() {
match T::VALID_ARGS {
ValidArgsTypes::Named(_) => panic!("`unnamed_arguments` arguments requested where only `Named` arguments are valid"),
ValidArgsTypes::Unnamed | ValidArgsTypes::Both { .. } => {},
ValidArgsTypes::None => panic!("`named_only` arguments requested where no arguments are valid")
}

Ok(UnnamedArgs::new(&self.unnamed))
} else {
Err(T::error("can be used with unnamed attributes only"))
Expand Down
20 changes: 19 additions & 1 deletion crates/snforge-scarb-plugin/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,25 @@ pub trait AttributeTypeData {
const CHEATCODE_NAME: &'static str;
}

pub trait AttributeCollector: AttributeInfo + AttributeTypeData {
pub enum ValidNamedArgs<'a> {
All,
Restricted(&'a [&'a str]),
}

pub enum ValidArgsTypes<'a> {
Named(ValidNamedArgs<'a>),
Unnamed,
Both {
valid_named_args: ValidNamedArgs<'a>,
},
None,
}

pub trait ValidArgs {
const VALID_ARGS: ValidArgsTypes<'_>;
}

pub trait AttributeCollector: AttributeInfo + AttributeTypeData + ValidArgs {
fn args_into_config_expression(
db: &dyn SyntaxGroup,
args: Arguments,
Expand Down
5 changes: 5 additions & 0 deletions crates/snforge-scarb-plugin/src/attributes/available_gas.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::attributes::{ValidArgs, ValidArgsTypes};
use crate::{
args::Arguments,
attributes::{AttributeCollector, AttributeInfo, AttributeTypeData},
Expand All @@ -18,6 +19,10 @@ impl AttributeTypeData for AvailableGasCollector {
const CHEATCODE_NAME: &'static str = "set_config_available_gas";
}

impl ValidArgs for AvailableGasCollector {
const VALID_ARGS: ValidArgsTypes<'_> = ValidArgsTypes::Unnamed;
}

impl AttributeCollector for AvailableGasCollector {
fn args_into_config_expression(
db: &dyn SyntaxGroup,
Expand Down
12 changes: 12 additions & 0 deletions crates/snforge-scarb-plugin/src/attributes/fork.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use self::block_id::{BlockId, BlockIdVariants};
use crate::attributes::{ValidArgs, ValidArgsTypes, ValidNamedArgs};
use crate::{
args::Arguments,
attributes::{AttributeCollector, AttributeInfo, AttributeTypeData},
Expand All @@ -24,6 +25,17 @@ impl AttributeTypeData for ForkCollector {
const CHEATCODE_NAME: &'static str = "set_config_fork";
}

impl ValidArgs for ForkCollector {
const VALID_ARGS: ValidArgsTypes<'_> = ValidArgsTypes::Both {
valid_named_args: ValidNamedArgs::Restricted(&[
"block_hash",
"block_number",
"block_tag",
"url",
]),
};
}

impl AttributeCollector for ForkCollector {
fn args_into_config_expression(
db: &dyn SyntaxGroup,
Expand Down
7 changes: 6 additions & 1 deletion crates/snforge-scarb-plugin/src/attributes/fuzzer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{AttributeInfo, AttributeTypeData};
use super::{AttributeInfo, AttributeTypeData, ValidArgs, ValidArgsTypes, ValidNamedArgs};
use crate::{
args::Arguments,
attributes::{AttributeCollector, ErrorExt},
Expand All @@ -20,6 +20,11 @@ impl AttributeTypeData for FuzzerCollector {
const CHEATCODE_NAME: &'static str = "set_config_fuzzer";
}

impl ValidArgs for FuzzerCollector {
const VALID_ARGS: ValidArgsTypes<'_> =
ValidArgsTypes::Named(ValidNamedArgs::Restricted(&["seed", "runs"]));
}

impl AttributeCollector for FuzzerCollector {
fn args_into_config_expression(
db: &dyn SyntaxGroup,
Expand Down
6 changes: 5 additions & 1 deletion crates/snforge-scarb-plugin/src/attributes/ignore.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{AttributeInfo, AttributeTypeData};
use super::{AttributeInfo, AttributeTypeData, ValidArgs, ValidArgsTypes};
use crate::{
args::Arguments, attributes::AttributeCollector,
config_statement::extend_with_config_cheatcodes,
Expand All @@ -16,6 +16,10 @@ impl AttributeTypeData for IgnoreCollector {
const CHEATCODE_NAME: &'static str = "set_config_ignore";
}

impl ValidArgs for IgnoreCollector {
const VALID_ARGS: ValidArgsTypes<'_> = ValidArgsTypes::None;
}

impl AttributeCollector for IgnoreCollector {
fn args_into_config_expression(
_db: &dyn SyntaxGroup,
Expand Down
6 changes: 6 additions & 0 deletions crates/snforge-scarb-plugin/src/attributes/should_panic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use self::expected::Expected;
use crate::attributes::{ValidArgs, ValidArgsTypes, ValidNamedArgs};
use crate::{
args::Arguments,
attributes::{AttributeCollector, AttributeInfo, AttributeTypeData},
Expand All @@ -21,6 +22,11 @@ impl AttributeTypeData for ShouldPanicCollector {
const CHEATCODE_NAME: &'static str = "set_config_should_panic";
}

impl ValidArgs for ShouldPanicCollector {
const VALID_ARGS: ValidArgsTypes<'_> =
ValidArgsTypes::Named(ValidNamedArgs::Restricted(&["expected"]));
}

impl AttributeCollector for ShouldPanicCollector {
fn args_into_config_expression(
db: &dyn SyntaxGroup,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ fn fails_with_non_number_literal() {
);
}

#[test]
fn fails_with_named() {
let item = TokenStream::new(EMPTY_FN.into());
let args = TokenStream::new(r#"(abc: "123")"#.into());

let result = available_gas(args, item);

assert_diagnostics(
&result,
&[Diagnostic::error(
"#[available_gas] can be used with unnamed attributes only",
)],
);
}

#[test]
fn work_with_number() {
let item = TokenStream::new(EMPTY_FN.into());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,29 @@ fn fails_with_invalid_url() {
);
}

#[test]
fn fails_with_unknown_argument() {
let item = TokenStream::new(EMPTY_FN.into());
let args = TokenStream::new(
r#"(url: "http://example.com", block_number: 23, unknow_arg: "value")"#.into(),
);

let result = fork(args, item);

assert_diagnostics(
&result,
&[Diagnostic::error(formatdoc!(
"
All options failed
- variant: #[fork] unsupported named argument \"unknow_arg\" provided
- variant: #[fork] expected 1 arguments, got: 0
- variant: #[fork] can be used with unnamed attributes only
Resolve at least one of them
"
))],
);
}

#[test]
fn accepts_string() {
let item = TokenStream::new(EMPTY_FN.into());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@ fn fail_with_invalid_args() {
);
}

#[test]
fn fail_with_unknown_arg() {
let item = TokenStream::new(EMPTY_FN.into());
let args = TokenStream::new("(seed: 1234, runs: 20, unknown_arg: 50)".into());

let result = fuzzer(args, item);

assert_diagnostics(
&result,
&[Diagnostic::error(
"#[fuzzer] unsupported named argument \"unknown_arg\" provided",
)],
);
}

#[test]
fn is_used_once() {
let item = TokenStream::new(formatdoc!(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,21 @@ fn work_with_expected_tuple() {
);
}

#[test]
fn fail_with_unknown_args() {
let item = TokenStream::new(EMPTY_FN.into());
let args = TokenStream::new("(expected: 'abc', unknown_arg: 'value')".into());

let result = should_panic(args, item);

assert_diagnostics(
&result,
&[Diagnostic::error(
"#[should_panic] unsupported named argument \"unknown_arg\" provided",
)],
);
}

#[test]
fn is_used_once() {
let item = TokenStream::new(formatdoc!(
Expand Down
Loading