genco 0.15.0

A whitespace-aware quasiquoter for beautiful code generation.
Documentation
//! Test to assert that the tokens generated are equivalent.

use genco::fmt;
use genco::prelude::*;
use genco::tokens::{Item::*, ItemStr::*};

#[test]
fn test_token_gen() {
    let tokens: rust::Tokens = quote! {
        foo
        bar
        baz
            #(ref tokens => quote_in! { *tokens => hello })
        out?
    };

    assert_eq! {
        vec![
            Literal(Static("foo")),
            Push,
            Literal(Static("bar")),
            Push,
            Literal(Static("baz")),
            Indentation(1),
            Literal(Static("hello")),
            Indentation(-1),
            Literal(Static("out?"))
        ],
        tokens,
    }
}

#[test]
fn test_iterator_gen() {
    let tokens: rust::Tokens = quote! {
        #(ref t => for n in 0..3 {
            t.push();
            t.append(n);
        })
    };

    assert_eq! {
        vec![
            Push,
            Literal(Box("0".into())),
            Push,
            Literal(Box("1".into())),
            Push,
            Literal(Box("2".into())),
        ],
        tokens,
    };

    let tokens: rust::Tokens = quote! {
        #(ref t {
            for n in 0..3 {
                t.push();
                t.append(n);
            }
        })
    };

    assert_eq! {
        vec![
            Push,
            Literal(Box("0".into())),
            Push,
            Literal(Box("1".into())),
            Push,
            Literal(Box("2".into())),
        ],
        tokens,
    };
}

#[test]
fn test_tricky_continuation() {
    let mut output = rust::Tokens::new();

    let bar = Static("bar");

    quote_in! {
        &mut output =>
        foo, #(ref output {
            output.append(&bar);
            output.append(Static(","));
            output.space();
        })baz
        biz
    };

    assert_eq! {
        output,
        vec![
            Literal(Static("foo,")),
            Space,
            Literal(Static("bar")),
            Literal(Static(",")),
            Space,
            Literal(Static("baz")),
            Push,
            Literal(Static("biz")),
        ]
    };
}

#[test]
fn test_indentation() {
    // Bug: Since we carry the span of out, the line after counts as unindented.
    //
    // These two should be identical:

    let mut a = rust::Tokens::new();

    quote_in! { a =>
        a
            b
        c
    };

    assert_eq! {
        a,
        vec![
            Literal(Static("a")),
            Indentation(1),
            Literal(Static("b")),
            Indentation(-1),
            Literal(Static("c"))
        ]
    };

    let mut b = rust::Tokens::new();

    quote_in! {
        b =>
        a
            b
        c
    };

    assert_eq! {
        b,
        vec![
            Literal(Static("a")),
            Indentation(1),
            Literal(Static("b")),
            Indentation(-1),
            Literal(Static("c"))
        ]
    };
}

#[test]
fn test_repeat() {
    let tokens: rust::Tokens = quote! {
        foo #(for (a, b) in (0..3).zip(3..6) => #a #b)
    };

    assert_eq! {
        vec![
            Literal(Static("foo")),
            Space,
            Literal("0".into()),
            Space,
            Literal("3".into()),
            Literal("1".into()),
            Space,
            Literal("4".into()),
            Literal("2".into()),
            Space,
            Literal("5".into())
        ],
        tokens,
    };

    let tokens: rust::Tokens = quote! {
        foo #(for (a, b) in (0..3).zip(3..6) { #a #b })
    };

    assert_eq! {
        vec![
            Literal(Static("foo")),
            Space,
            Literal("0".into()),
            Space,
            Literal("3".into()),
            Literal("1".into()),
            Space,
            Literal("4".into()),
            Literal("2".into()),
            Space,
            Literal("5".into())
        ],
        tokens,
    };
}

#[test]
fn test_tight_quote() {
    let output: rust::Tokens = quote! {
        You are:#("fine")
    };

    assert_eq! {
        output,
        vec![
            Literal(Static("You")),
            Space,
            Literal(Static("are:fine")),
        ]
    };
}

#[test]
fn test_tight_repitition() {
    let output: rust::Tokens = quote! {
        You are: #(for v in 0..3 join (, ) => #v)
    };

    assert_eq! {
        output,
        vec![
            Literal(Static("You")),
            Space,
            Literal(Static("are:")),
            Space,
            Literal("0".into()),
            Literal(Static(",")),
            Space,
            Literal("1".into()),
            Literal(Static(",")),
            Space,
            Literal("2".into()),
        ]
    };
}

#[test]
fn test_if() {
    let a = true;
    let b = false;

    let output: rust::Tokens = quote! {
        #(if a => foo)
        #(if a { foo2 })
        #(if b { bar })
        #(if b => bar2)
        #(if a => baz)
        #(if a { baz2 })
        #(if b { not_biz } else { biz })
    };

    assert_eq! {
        output,
        vec![
            Literal(Static("foo")),
            Push,
            Literal(Static("foo2")),
            Push,
            Literal(Static("baz")),
            Push,
            Literal(Static("baz2")),
            Push,
            Literal(Static("biz")),
        ]
    };
}

#[test]
fn test_match() {
    enum Alt {
        A,
        B,
    }

    fn test(alt: Alt) -> rust::Tokens {
        quote! {
            #(match alt { Alt::A => a, Alt::B => b })
        }
    }

    fn test2(alt: Alt) -> rust::Tokens {
        quote! {
            #(match alt { Alt::A => { a }, Alt::B => { b } })
        }
    }

    fn test2_cond(alt: Alt, cond: bool) -> rust::Tokens {
        quote! {
            #(match alt { Alt::A if cond => { a }, _ => { b } })
        }
    }

    assert_eq! {
        test(Alt::A),
        vec![Literal(Static("a"))]
    };

    assert_eq! {
        test(Alt::B),
        vec![Literal(Static("b"))]
    };

    assert_eq! {
        test2(Alt::A),
        vec![Literal(Static("a"))]
    };

    assert_eq! {
        test2(Alt::B),
        vec![Literal(Static("b"))]
    };

    assert_eq! {
        test2_cond(Alt::A, true),
        vec![Literal(Static("a"))]
    };

    assert_eq! {
        test2_cond(Alt::A, false),
        vec![Literal(Static("b"))]
    };
}

#[test]
fn test_empty_loop_whitespace() {
    // Bug: This should generate two commas. But did generate a space following
    // it!
    let tokens: rust::Tokens = quote! {
        #(for _ in 0..3 join(,) =>)
    };

    assert_eq! {
        tokens,
        vec![Literal(Static(",")), Literal(Static(","))]
    };

    let tokens: rust::Tokens = quote! {
        #(for _ in 0..3 join( ,) =>)
    };

    assert_eq! {
        tokens,
        vec![Space, Literal(Static(",")), Space, Literal(Static(","))]
    };

    let tokens: rust::Tokens = quote! {
          #(for _ in 0..3 join(, ) =>)
    };

    assert_eq! {
        tokens,
        vec![Literal(Static(",")), Space, Literal(Static(",")), Space]
    };

    let tokens: rust::Tokens = quote! {
          #(for _ in 0..3 join( , ) =>)
    };

    assert_eq! {
        tokens,
        vec![Space, Literal(Static(",")), Space, Literal(Static(",")), Space]
    };
}

#[test]
fn test_indentation_empty() {
    let tokens: rust::Tokens = quote! {
        a
            #(for _ in 0..3 =>)
        b
    };

    assert_eq! {
        tokens,
        vec![
            Literal(Static("a")),
            Literal(Static("b"))
        ]
    };

    let tokens: rust::Tokens = quote! {
        a
            #(if false {})
        b
    };

    assert_eq! {
        tokens,
        vec![
            Literal(Static("a")),
            Literal(Static("b"))
        ]
    };

    let tokens: rust::Tokens = quote! {
        a
            #(ref _tokens =>)
        b
    };

    assert_eq! {
        tokens,
        vec![
            Literal(Static("a")),
            Literal(Static("b"))
        ]
    };
}

#[test]
fn test_indentation_management() {
    let tokens: rust::Tokens = quote! {
        if a:
            if b:
                foo
        else:
            c
    };

    assert_eq! {
        vec![
            Literal(Static("if")),
            Space,
            Literal(Static("a:")),
            Indentation(1),
            Literal(Static("if")),
            Space,
            Literal(Static("b:")),
            Indentation(1),
            Literal(Static("foo")),
            Indentation(-2),
            Literal(Static("else:")),
            Indentation(1),
            Literal(Static("c")),
            Indentation(-1)
        ],
        tokens,
    };

    let tokens: rust::Tokens = quote! {
        if a:
            if b:
                foo

        #(if false => bar)

        #(if true => baz)
    };

    assert_eq! {
        vec![
            Literal(Static("if")),
            Space,
            Literal(Static("a:")),
            Indentation(1),
            Literal(Static("if")),
            Space,
            Literal(Static("b:")),
            Indentation(1),
            Literal(Static("foo")),
            Indentation(-2),
            Line,
            Literal(Static("baz")),
        ],
        tokens,
    };
}

#[test]
fn test_indentation_management2() -> fmt::Result {
    let tokens: python::Tokens = quote! {
        def foo():
            pass

        def bar():
            pass
    };

    assert_eq! {
        vec![
            Literal(Static("def")),
            Space,
            Literal(Static("foo():")),
            Indentation(1),
            Literal(Static("pass")),
            Indentation(-1),
            Line,
            Literal(Static("def")),
            Space,
            Literal(Static("bar():")),
            Indentation(1),
            Literal(Static("pass")),
            Indentation(-1)
        ],
        tokens.clone(),
    };

    assert_eq!(
        vec!["def foo():", "    pass", "", "def bar():", "    pass",],
        tokens.to_file_vec()?
    );

    Ok(())
}

#[test]
fn test_lines() -> fmt::Result {
    let mut tokens: rust::Tokens = quote! {
        fn foo() {
        }
    };

    tokens.line();

    quote_in! { tokens =>
        #(if false =>)
        fn bar() {
        }
    };

    assert_eq! {
        vec![
            Literal(Static("fn")),
            Space,
            Literal(Static("foo()")),
            Space,
            Literal(Static("{")),
            Push,
            Literal(Static("}")),
            Line,
            Literal(Static("fn")),
            Space,
            Literal(Static("bar()")),
            Space,
            Literal(Static("{")),
            Push,
            Literal(Static("}"))
        ],
        tokens.clone(),
    };

    assert_eq!(
        vec!["fn foo() {", "}", "", "fn bar() {", "}",],
        tokens.to_file_vec()?
    );

    Ok(())
}