rulewright 0.1.2

Executable engineering standards for Rust workspaces
Documentation
use super::*;

crate::rulewright_test!(check_aligned, {
    crate::example_tests!(EXAMPLES, check_aligned);
    crate::fix_tests!(EXAMPLES, line, check_aligned, fix_aligned);

    #[gtest]
    fn arrow_aligned_passes() -> Result<()> {
        let v = run("// #rw:aligned\n\
             Parser    => \"cleanup_parser.sql\";\n\
             Writer    => \"cleanup_traits.sql\";\n\
             Files     => \"cleanup_items.sql\";");
        verify_true!(v.is_empty())?;

        Ok(())
    }

    #[gtest]
    fn arrow_misaligned_fails() -> Result<()> {
        let v = run("// #rw:aligned\n\
             Parser    => \"cleanup_parser.sql\";\n\
             Writer => \"cleanup_traits.sql\";\n\
             Files     => \"cleanup_items.sql\";");
        verify_eq!(v.len(), 1)?;
        verify_eq!(v[0].line, 3)?;
        verify_true!(v[0].message.contains("=>"))?;

        Ok(())
    }

    #[gtest]
    fn comma_aligned_passes() -> Result<()> {
        let v = run("// #rw:aligned\n\
             register!(A,  \"a\",  TypeA);\n\
             register!(B,  \"b\",  TypeB);\n\
             register!(C,  \"c\",  TypeC);");
        verify_true!(v.is_empty())?;

        Ok(())
    }

    #[gtest]
    fn comma_misaligned_fails() -> Result<()> {
        let v = run("// #rw:aligned\n\
             register!(A,  \"a\",  TypeA);\n\
             register!(B, \"b\", TypeB);\n\
             register!(C,  \"c\",  TypeC);");
        verify_false!(v.is_empty())?;

        Ok(())
    }

    #[gtest]
    fn trailing_commas_are_aligned() -> Result<()> {
        let source = "// #rw:aligned\n\
             \"id\": Int,\n\
             \"patch_version\": Text,\n\
             \"cloth_modifier\": Float,";
        let fixed = crate::apply_line_fixes(source, check_aligned, fix_aligned);

        verify_true!(run(&fixed).is_empty())?;

        Ok(())
    }

    #[gtest]
    fn skips_comments_in_block() -> Result<()> {
        let v = run("// #rw:aligned\n\
             Parser => \"a\";\n\
             // comment\n\
             Writer => \"b\";");
        verify_true!(v.is_empty())?;

        Ok(())
    }

    #[gtest]
    fn block_ends_at_blank_line() -> Result<()> {
        let v = run("// #rw:aligned\n\
             Parser => \"a\";\n\
             Writer => \"b\";\n\
             \n\
             Misaligned => \"c\";");
        verify_true!(v.is_empty())?;

        Ok(())
    }

    #[gtest]
    fn block_ends_at_closing_delim() -> Result<()> {
        let v = run("// #rw:aligned\n\
             Parser => \"a\";\n\
             Writer => \"b\";\n\
             );");
        verify_true!(v.is_empty())?;

        Ok(())
    }

    #[gtest]
    fn block_ends_at_array_closing_delim() -> Result<()> {
        let v = run("// #rw:aligned\n\
             (1, 2),\n\
             (3, 4),\n\
             ];\n\
             call(a, b, c);");
        verify_true!(v.is_empty())?;

        Ok(())
    }

    #[gtest]
    fn block_ends_at_macro_array_closing_delim() -> Result<()> {
        let v = run("// #rw:aligned\n\
             \"id\": Int,\n\
             \"x\": Text,\n\
             ]);");
        verify_true!(v.is_empty())?;

        Ok(())
    }

    #[gtest]
    fn no_marker_no_violations() -> Result<()> {
        let v = run("Parser    => \"a\";\n\
             Writer => \"b\";");
        verify_true!(v.is_empty())?;

        Ok(())
    }

    #[gtest]
    fn marker_inside_raw_string_is_ignored() -> Result<()> {
        let source = r##"const SOURCE: &str = r#"
// #rw:aligned
(SHORT, "first"),
(MUCH_LONGER_NAME, "second"),
"#;"##;

        verify_true!(run(source).is_empty())
    }

    #[gtest]
    fn comma_inside_string_ignored() -> Result<()> {
        let v = run("// #rw:aligned\n\
             call(a, \"hello, world\", b);\n\
             call(c, \"hello, world\", d);");
        verify_true!(v.is_empty())?;

        Ok(())
    }

    #[gtest]
    fn mismatched_comma_count() -> Result<()> {
        let v = run("// #rw:aligned\n\
             call(a, b, c);\n\
             call(a, b, c);\n\
             call(a, b);");
        verify_eq!(v.len(), 1)?;
        verify_true!(v[0].message.contains("aligned fields"))?;

        Ok(())
    }

    #[gtest]
    fn wrapped_tuple_rows_fix_to_one_aligned_row_each() -> Result<()> {
        let source = "let cases = [\n    // #rw:aligned\n    (\n        SHORT,\n        \"first\",\n    ),\n    (LONG_NAME, \"second\"),\n];";
        let expected = "let cases = [\n    // #rw:aligned\n    (SHORT,     \"first\"),\n    (LONG_NAME, \"second\"),\n];";

        verify_eq!(
            crate::apply_line_fixes(source, check_aligned, fix_aligned),
            expected
        )
    }

    #[gtest]
    fn longest_tuple_field_sets_the_aligned_column() -> Result<()> {
        let source = "let cases = [\n    // #rw:aligned\n    (SHORT,            \"first\"),\n    (MUCH_LONGER_NAME, \"second\"),\n    (MEDIUM,           \"third\"),\n];";
        let misaligned = "let cases = [\n    // #rw:aligned\n    (SHORT, \"first\"),\n    (MUCH_LONGER_NAME, \"second\"),\n    (MEDIUM, \"third\"),\n];";

        verify_false!(run(misaligned).is_empty())?;
        verify_eq!(
            crate::apply_line_fixes(misaligned, check_aligned, fix_aligned),
            source
        )?;

        verify_true!(run(source).is_empty())
    }

    #[gtest]
    fn wrapped_tuple_with_nested_expression_has_no_fix() -> Result<()> {
        let source = "let cases = [\n    // #rw:aligned\n    (\n        SHORT,\n        build(value),\n    ),\n    (LONG_NAME, other),\n];";

        verify_false!(run(source).is_empty())?;
        verify_eq!(
            crate::apply_line_fixes(source, check_aligned, fix_aligned),
            source
        )
    }

    #[gtest]
    fn wrapped_tuple_with_block_expression_has_no_fix() -> Result<()> {
        let source = "let cases = [\n    // #rw:aligned\n    (\n        SHORT,\n        { compute() },\n    ),\n    (LONG_NAME, other),\n];";

        verify_false!(run(source).is_empty())?;
        verify_eq!(
            crate::apply_line_fixes(source, check_aligned, fix_aligned),
            source
        )
    }

    #[gtest]
    fn majority_ties_choose_the_smaller_column() -> Result<()> {
        verify_eq!(majority([12, 8].into_iter()), 8)?;

        let violations = run("// #rw:aligned\nShort => one,\nLongName => two,");

        verify_eq!(violations.len(), 1)?;
        verify_eq!(violations[0].line, 3)
    }
});