opened
PabloSichert
username_0
Hey there!

I have a struct that implements `Parse`

```rust
impl Parse for Foo {
    fn parse(input: ParseStream) -> Result<Self> {
        ···
    }
}
```

which I would like to unit-test.

The story is quite easy for legal input:

```rust
fn assert_expression_eq<T: Parse + ToTokens>(
    input: &str,
    expected: &str,
) -> Result<(), Box<dyn Error>> {
    let element = parse_str::<T>(input)?;
    let expanded = quote!(#element).to_string();
    let actual_fmt = fmt_expression(&expanded)?;
    let expected_fmt = fmt_expression(&expected)?;

    if actual_fmt == expected_fmt {
        Ok(())
    } else {
        Err(Box::new(AssertionError::new(expected_fmt, actual_fmt)))
    }
}
```

However, I would also like to maintain fixtures with test cases where the parser is supposed to fail.

Something like:

```rust
fn assert_parse_error<T: Parse + ToTokens>(
    input: &str,
    error: &str,
) -> Result<(), Box<dyn Error>> {
    ···
}
```

However, when I force an error while parsing, I get

```
thread '···' panicked at 'proc_macro::Span is only available in procedural macros', ···/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.30/src/wrapper.rs:467:34
```

I also tried mocking a procedural macro by creating a `TokenStream` and feeding it to `parse_macro_input`:

```rust
fn try_parse<T: Parse + ToTokens>(
    input: &str
) -> proc_macro::TokenStream {
    let tokens = proc_macro::TokenStream::from_str(input).unwrap();
    let element = parse_macro_input!(tokens as T);

    proc_macro::TokenStream::from(quote!(#element))
}
```

which results in

```
thread '···' panicked at 'procedural macro API is used outside of a procedural macro', src/libproc_macro/bridge/client.rs:315:17
```

Is there any recommended approach to what I'm trying? I didn't find any resources searching the documentation and issues.

---

P.S.: Thanks for this library, it's incredibly straight-forward to use and makes meta-programming super fun
Unit testing illegal input / parser errors
issue
created
dtolnay
username_1
The types in proc-macro can't exist in a unit test. You will need to use proc-macro2:
https://docs.rs/proc-macro2
comment
created
PabloSichert
username_0
Seems like this was the culprit in my code (unwrapping `Span`s to join them):

```rust
fn parse(input: ParseStream) -> Result<Self> {
    ···

    if component_type_closing_string != component_type_opening_string {
        let span_opening = component_type.span().unwrap();
        let span_closing = component_type_closing.span().unwrap();

        span_opening
            .join(span_closing)
            .unwrap()
            .error(
                "expected matching closing tag </".to_owned()
                    + &component_type_opening_string
                    + ">, found </"
                    + &component_type_closing_string
                    + ">",
            )
            .emit();
    }

    ···
}
```

The soution (as of today) is to set `RUSTFLAGS='--cfg procmacro2_semver_exempt'` and use [`proc_macro2::Span::join`](https://docs.rs/proc-macro2/0.4.30/proc_macro2/struct.Span.html#method.join)/[`syn::Error`](https://docs.rs/syn/0.15.39/syn/struct.Error.html) instead.

```rust
fn parse(input: ParseStream) -> Result<Self> {
    ···

    if component_type_closing_string != component_type_opening_string {
        let span_opening = component_type.span();
        let span_closing = component_type_closing.span();
        let span = span_opening.join(span_closing).unwrap();

        return Err(Error::new(
            span,
            "expected matching closing tag </".to_owned()
                + &component_type_opening_string
                + ">, found </"
                + &component_type_closing_string
                + ">",
        ));
    }

    ···
}
```
comment
closed
PabloSichert
username_0
issue