use super::*;

pub(super) const P0034_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0034_01.uc",
        source: "switch(A) local\n",
    },
    Fixture {
        label: "files/P0034_02.uc",
        source: "switch\n(A)\nvar",
    },
    Fixture {
        label: "files/P0034_03.uc",
        source: "switch(\n    A\n)\n",
    },
    Fixture {
        label: "files/P0034_04.uc",
        source: "switch\n(\n    A\n)\n",
    },
    Fixture {
        label: "files/P0034_05.uc",
        source: "switch(A)\ncase 1:\n",
    },
];

#[test]
fn check_p0034_fixtures() {
    let runs = run_fixtures(P0034_FIXTURES);

    assert_eq!(runs.get("files/P0034_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0034_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0034_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0034_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0034_05.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0034_01.uc"),
        &ExpectedDiagnostic {
            headline: "missing `{` to start `switch` body",
            severity: Severity::Error,
            code: Some("P0034"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "expected `{` before `local`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0034_02.uc"),
        &ExpectedDiagnostic {
            headline: "missing `{` to start `switch` body",
            severity: Severity::Error,
            code: Some("P0034"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(6),
                },
                message: "expected `{` before `var`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0034_03.uc"),
        &ExpectedDiagnostic {
            headline: "missing `{` to start `switch` body",
            severity: Severity::Error,
            code: Some("P0034"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(8),
                },
                message: "expected `{` after the switch expression",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0034_04.uc"),
        &ExpectedDiagnostic {
            headline: "missing `{` to start `switch` body",
            severity: Severity::Error,
            code: Some("P0034"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(9),
                },
                message: "expected `{` after the switch expression",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0034_05.uc"),
        &ExpectedDiagnostic {
            headline: "missing `{` to start `switch` body",
            severity: Severity::Error,
            code: Some("P0034"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(5),
                },
                message: "expected `{` before `case`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0035_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0035_01.uc",
        source: "switch(A) {\n    Log(\"bad\");\n}\n",
    },
    Fixture {
        label: "files/P0035_02.uc",
        source: "switch\n(A)\n{\n    Log(\"bad\");\n  Log(\"worse\");\n  case 1:\n}\n",
    },
    Fixture {
        label: "files/P0035_03.uc",
        source: "switch(A) {\n    123;\n    default:\n}\n",
    },
    Fixture {
        label: "files/P0035_04.uc",
        source: "switch\n(\n    A\n)\n{\n    if (A) {}\n    case 1:\n}\n",
    },
    Fixture {
        label: "files/P0035_05.uc",
        source: "switch(A) {\n    {\n        Log(\"nested\");\n    }\n    case 1:\n}\n",
    },
];

#[test]
fn check_p0035_fixtures() {
    let runs = run_fixtures(P0035_FIXTURES);

    assert_eq!(runs.get("files/P0035_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0035_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0035_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0035_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0035_05.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0035_01.uc"),
        &ExpectedDiagnostic {
            headline: "expected `case` or `default` section label in switch body",
            severity: Severity::Error,
            code: Some("P0035"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(8),
                    end: TokenPosition(12),
                },
                message: "this statement must be inside a `case` or `default` section",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(5),
                        end: TokenPosition(5),
                    },
                    message: "switch body starts here",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0035_02.uc"),
        &ExpectedDiagnostic {
            headline: "expected `case` or `default` section label in switch body",
            severity: Severity::Error,
            code: Some("P0035"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(9),
                    end: TokenPosition(20),
                },
                message: "these statements must be inside a `case` or `default` section",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(0),
                        end: TokenPosition(0),
                    },
                    message: "`switch` starts here",
                },
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(6),
                        end: TokenPosition(6),
                    },
                    message: "switch body starts here",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0035_03.uc"),
        &ExpectedDiagnostic {
            headline: "expected `case` or `default` section label in switch body",
            severity: Severity::Error,
            code: Some("P0035"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(8),
                    end: TokenPosition(9),
                },
                message: "this statement must be inside a `case` or `default` section",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(5),
                        end: TokenPosition(5),
                    },
                    message: "switch body starts here",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0035_04.uc"),
        &ExpectedDiagnostic {
            headline: "expected `case` or `default` section label in switch body",
            severity: Severity::Error,
            code: Some("P0035"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(12),
                    end: TokenPosition(19),
                },
                message: "this statement must be inside a `case` or `default` section",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(0),
                        end: TokenPosition(0),
                    },
                    message: "`switch` starts here",
                },
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(9),
                        end: TokenPosition(9),
                    },
                    message: "switch body starts here",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0035_05.uc"),
        &ExpectedDiagnostic {
            headline: "expected `case` or `default` section label in switch body",
            severity: Severity::Error,
            code: Some("P0035"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(8),
                    end: TokenPosition(18),
                },
                message: "this block must be inside a `case` or `default` section",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(5),
                        end: TokenPosition(5),
                    },
                    message: "switch body starts here",
                },
            ],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0036_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0036_01.uc",
        source: "switch(A) {\n    case 1\n    case 2:\n}\n",
    },
    Fixture {
        label: "files/P0036_02.uc",
        source: "switch\n(A)\n{\n    case\n        1\n    default:\n}\n",
    },
    Fixture {
        label: "files/P0036_03.uc",
        source: "switch(A) {\n    case (A)\n    case B:\n}\n",
    },
    Fixture {
        label: "files/P0036_04.uc",
        source: "switch\n(\n    A\n)\n{\n    case\n        A + B\n    default\n        :\n}\n",
    },
    Fixture {
        label: "files/P0036_05.uc",
        source: "switch(A) {\n    case Foo.Bar(Baz)\n    case Other:\n}\n",
    },
];

#[test]
fn check_p0036_fixtures() {
    let runs = run_fixtures(P0036_FIXTURES);

    assert_eq!(runs.get("files/P0036_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0036_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0036_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0036_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0036_05.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0036_01.uc"),
        &ExpectedDiagnostic {
            headline: "missing `:` after `case` label",
            severity: Severity::Error,
            code: Some("P0036"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(13),
                    end: TokenPosition(13),
                },
                message: "expected `:` before `case`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(10),
                    },
                    message: "this `case` label needs a trailing `:`",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0036_02.uc"),
        &ExpectedDiagnostic {
            headline: "missing `:` after `case` label",
            severity: Severity::Error,
            code: Some("P0036"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(15),
                    end: TokenPosition(15),
                },
                message: "expected `:` before `default`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(9),
                        end: TokenPosition(12),
                    },
                    message: "this `case` label needs a trailing `:`",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0036_03.uc"),
        &ExpectedDiagnostic {
            headline: "missing `:` after `case` label",
            severity: Severity::Error,
            code: Some("P0036"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(15),
                    end: TokenPosition(15),
                },
                message: "expected `:` before `case`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(12),
                    },
                    message: "this `case` label needs a trailing `:`",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0036_04.uc"),
        &ExpectedDiagnostic {
            headline: "missing `:` after `case` label",
            severity: Severity::Error,
            code: Some("P0036"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(22),
                    end: TokenPosition(22),
                },
                message: "expected `:` before `default`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(12),
                        end: TokenPosition(19),
                    },
                    message: "this `case` label needs a trailing `:`",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0036_05.uc"),
        &ExpectedDiagnostic {
            headline: "missing `:` after `case` label",
            severity: Severity::Error,
            code: Some("P0036"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(18),
                    end: TokenPosition(18),
                },
                message: "expected `:` before `case`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(15),
                    },
                    message: "this `case` label needs a trailing `:`",
                },
            ],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0037_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0037_01.uc",
        source: "switch(A) {\n    default\n    if (A) {}\n}\n",
    },
    Fixture {
        label: "files/P0037_02.uc",
        source: "switch\n(A)\n{\n    default\n    while (A) {}\n}\n",
    },
    Fixture {
        label: "files/P0037_03.uc",
        source: "switch(A) {\n    default\n    for (;;) {}\n}\n",
    },
    Fixture {
        label: "files/P0037_04.uc",
        source: "switch\n(\n    A\n)\n{\n    default\n    switch(B) {\n        case 1:\n    }\n}\n",
    },
    Fixture {
        label: "files/P0037_05.uc",
        source: "switch(A) {\n    default\n    case 1:\n}\n",
    },
];

#[test]
fn check_p0037_fixtures() {
    let runs = run_fixtures(P0037_FIXTURES);

    assert_eq!(runs.get("files/P0037_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0037_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0037_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0037_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0037_05.uc").unwrap().len(), 2);

    assert_diagnostic(
        &runs.get_any("files/P0037_01.uc"),
        &ExpectedDiagnostic {
            headline: "missing `:` after `default`",
            severity: Severity::Error,
            code: Some("P0037"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(11),
                    end: TokenPosition(11),
                },
                message: "expected `:` before `if`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(8),
                    },
                    message: "this `default` label needs a trailing `:`",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0037_02.uc"),
        &ExpectedDiagnostic {
            headline: "missing `:` after `default`",
            severity: Severity::Error,
            code: Some("P0037"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(12),
                    end: TokenPosition(12),
                },
                message: "expected `:` before `while`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(9),
                        end: TokenPosition(9),
                    },
                    message: "this `default` label needs a trailing `:`",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0037_03.uc"),
        &ExpectedDiagnostic {
            headline: "missing `:` after `default`",
            severity: Severity::Error,
            code: Some("P0037"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(11),
                    end: TokenPosition(11),
                },
                message: "expected `:` before `for`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(8),
                    },
                    message: "this `default` label needs a trailing `:`",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0037_04.uc"),
        &ExpectedDiagnostic {
            headline: "missing `:` after `default`",
            severity: Severity::Error,
            code: Some("P0037"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(15),
                    end: TokenPosition(15),
                },
                message: "expected `:` before `switch`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(12),
                        end: TokenPosition(12),
                    },
                    message: "this `default` label needs a trailing `:`",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0037_05.uc", "P0037"),
        &ExpectedDiagnostic {
            headline: "missing `:` after `default`",
            severity: Severity::Error,
            code: Some("P0037"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(11),
                    end: TokenPosition(11),
                },
                message: "expected `:` before `case`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(8),
                    },
                    message: "this `default` label needs a trailing `:`",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0037_05.uc", "P0039"),
        &ExpectedDiagnostic {
            headline: "`case` section appears after `default`",
            severity: Severity::Error,
            code: Some("P0039"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(11),
                    end: TokenPosition(11),
                },
                message: "`case` after `default`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(8),
                    },
                    message: "`default` must be the last section in this switch",
                },
            ],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0038_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0038_01.uc",
        source: "switch(A) {\n    default:\n    default:\n}\n",
    },
    Fixture {
        label: "files/P0038_02.uc",
        source: "switch\n(A)\n{\n    default\n        :\n    default\n        :\n}\n",
    },
    Fixture {
        label: "files/P0038_03.uc",
        source: "switch(A) {\n    default:\n    default:\n    default:\n}\n",
    },
    Fixture {
        label: "files/P0038_04.uc",
        source: "switch\n(\n    A\n)\n{\n    default:\n        Log(\"first\");\n    default:\n        Log(\"second\");\n}\n",
    },
];

#[test]
fn check_p0038_fixtures() {
    let runs = run_fixtures(P0038_FIXTURES);

    assert_eq!(runs.get("files/P0038_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0038_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0038_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0038_04.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0038_01.uc"),
        &ExpectedDiagnostic {
            headline: "duplicate `default` section in switch",
            severity: Severity::Error,
            code: Some("P0038"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(12),
                    end: TokenPosition(12),
                },
                message: "duplicate `default` section",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(8),
                    },
                    message: "first `default` section is here",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0038_02.uc"),
        &ExpectedDiagnostic {
            headline: "duplicate `default` section in switch",
            severity: Severity::Error,
            code: Some("P0038"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(15),
                    end: TokenPosition(15),
                },
                message: "duplicate `default` section",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(9),
                        end: TokenPosition(9),
                    },
                    message: "first `default` section is here",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0038_03.uc"),
        &ExpectedDiagnostic {
            headline: "multiple `default` sections in switch",
            severity: Severity::Error,
            code: Some("P0038"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(12),
                    end: TokenPosition(12),
                },
                message: "duplicate `default` section",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(8),
                    },
                    message: "first `default` section is here",
                },
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(16),
                        end: TokenPosition(16),
                    },
                    message: "another duplicate `default` section",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0038_04.uc"),
        &ExpectedDiagnostic {
            headline: "duplicate `default` section in switch",
            severity: Severity::Error,
            code: Some("P0038"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(23),
                    end: TokenPosition(23),
                },
                message: "duplicate `default` section",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(12),
                        end: TokenPosition(12),
                    },
                    message: "first `default` section is here",
                },
            ],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0039_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0039_01.uc",
        source: "switch(A) {\n    default:\n    case 1:\n}\n",
    },
    Fixture {
        label: "files/P0039_02.uc",
        source: "switch\n(A)\n{\n    default\n        :\n    case\n        1\n        :\n}\n",
    },
    Fixture {
        label: "files/P0039_03.uc",
        source: "switch(A) {\n    default:\n    case 1:\n    case 2:\n}\n",
    },
    Fixture {
        label: "files/P0039_04.uc",
        source: "switch\n(\n    A\n)\n{\n    default:\n    case 1:\n        Log(\"one\");\n    case 2:\n        Log(\"two\");\n}\n",
    },
    Fixture {
        label: "files/P0039_05.uc",
        source: "switch(A) {\n    default:\n        Log(\"done\");\n    case 1:\n    case 2:\n        Log(\"stacked\");\n}\n",
    },
];

#[test]
fn check_p0039_fixtures() {
    let runs = run_fixtures(P0039_FIXTURES);

    assert_eq!(runs.get("files/P0039_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0039_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0039_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0039_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0039_05.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0039_01.uc"),
        &ExpectedDiagnostic {
            headline: "`case` section appears after `default`",
            severity: Severity::Error,
            code: Some("P0039"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(12),
                    end: TokenPosition(12),
                },
                message: "`case` after `default`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(8),
                    },
                    message: "`default` must be the last section in this switch",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0039_02.uc"),
        &ExpectedDiagnostic {
            headline: "`case` section appears after `default`",
            severity: Severity::Error,
            code: Some("P0039"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(15),
                    end: TokenPosition(15),
                },
                message: "`case` after `default`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(9),
                        end: TokenPosition(9),
                    },
                    message: "`default` must be the last section in this switch",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0039_03.uc"),
        &ExpectedDiagnostic {
            headline: "`case` section appears after `default`",
            severity: Severity::Error,
            code: Some("P0039"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(12),
                    end: TokenPosition(12),
                },
                message: "`case` after `default`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(8),
                    },
                    message: "`default` must be the last section in this switch",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0039_04.uc"),
        &ExpectedDiagnostic {
            headline: "multiple `case` sections appear after `default`",
            severity: Severity::Error,
            code: Some("P0039"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(16),
                    end: TokenPosition(16),
                },
                message: "`case` after `default`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(12),
                        end: TokenPosition(12),
                    },
                    message: "`default` must be the last section in this switch",
                },
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(29),
                        end: TokenPosition(29),
                    },
                    message: "another `case` after `default`",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0039_05.uc"),
        &ExpectedDiagnostic {
            headline: "`case` section appears after `default`",
            severity: Severity::Error,
            code: Some("P0039"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(19),
                    end: TokenPosition(19),
                },
                message: "`case` after `default`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(8),
                    },
                    message: "`default` must be the last section in this switch",
                },
            ],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0040_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0040_01.uc",
        source: "switch(A) {\n",
    },
    Fixture {
        label: "files/P0040_02.uc",
        source: "switch(A) {\n    case 1:\n",
    },
    Fixture {
        label: "files/P0040_03.uc",
        source: "switch\n(A)\n{\n    default:\n",
    },
    Fixture {
        label: "files/P0040_04.uc",
        source: "switch\n(\n    A\n)\n{\n    case 1:\n    case 2:\n",
    },
    Fixture {
        label: "files/P0040_05.uc",
        source: "switch(A) {\n    case 1:\n        Log(\"body\");\n",
    },
];

#[test]
fn check_p0040_fixtures() {
    let runs = run_fixtures(P0040_FIXTURES);

    assert_eq!(runs.get("files/P0040_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0040_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0040_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0040_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0040_05.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0040_01.uc"),
        &ExpectedDiagnostic {
            headline: "missing `}` to close switch body",
            severity: Severity::Error,
            code: Some("P0040"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "expected `}` before end of file",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0040_02.uc"),
        &ExpectedDiagnostic {
            headline: "missing `}` to close switch body",
            severity: Severity::Error,
            code: Some("P0040"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(13),
                },
                message: "expected `}` before end of file",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0040_03.uc"),
        &ExpectedDiagnostic {
            headline: "missing `}` to close switch body",
            severity: Severity::Error,
            code: Some("P0040"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(6),
                    end: TokenPosition(12),
                },
                message: "expected `}` before end of file",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(0),
                        end: TokenPosition(0),
                    },
                    message: "`switch` starts here",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0040_04.uc"),
        &ExpectedDiagnostic {
            headline: "missing `}` to close switch body",
            severity: Severity::Error,
            code: Some("P0040"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(9),
                    end: TokenPosition(23),
                },
                message: "expected `}` before end of file",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(0),
                        end: TokenPosition(0),
                    },
                    message: "`switch` starts here",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0040_05.uc"),
        &ExpectedDiagnostic {
            headline: "missing `}` to close switch body",
            severity: Severity::Error,
            code: Some("P0040"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(20),
                },
                message: "expected `}` before end of file",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0041_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0041_01.uc",
        source: "switch(A) {\n    case:\n}\n",
    },
    Fixture {
        label: "files/P0041_02.uc",
        source: "switch\n(A)\n{\n    case\n        :\n}\n",
    },
    Fixture {
        label: "files/P0041_03.uc",
        source: "switch(A) {\n    case:\n    default:\n}\n",
    },
    Fixture {
        label: "files/P0041_04.uc",
        source: "switch\n(\n    A\n)\n{\n    case\n        :\n    case 1:\n}\n",
    },
    Fixture {
        label: "files/P0041_05.uc",
        source: "switch(A) {\n    case\n        :\n    default:\n}\n",
    },
];

#[test]
fn check_p0041_fixtures() {
    let runs = run_fixtures(P0041_FIXTURES);

    assert_eq!(runs.get("files/P0041_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0041_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0041_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0041_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0041_05.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0041_01.uc"),
        &ExpectedDiagnostic {
            headline: "missing expression after `case`",
            severity: Severity::Error,
            code: Some("P0041"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(9),
                    end: TokenPosition(9),
                },
                message: "expected expression before `:`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0041_02.uc"),
        &ExpectedDiagnostic {
            headline: "missing expression after `case`",
            severity: Severity::Error,
            code: Some("P0041"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(12),
                    end: TokenPosition(12),
                },
                message: "expected expression before `:`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(9),
                        end: TokenPosition(9),
                    },
                    message: "after this `case`, an expression was expected",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0041_03.uc"),
        &ExpectedDiagnostic {
            headline: "missing expression after `case`",
            severity: Severity::Error,
            code: Some("P0041"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(9),
                    end: TokenPosition(9),
                },
                message: "expected expression before `:`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0041_04.uc"),
        &ExpectedDiagnostic {
            headline: "missing expression after `case`",
            severity: Severity::Error,
            code: Some("P0041"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(15),
                    end: TokenPosition(15),
                },
                message: "expected expression before `:`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(12),
                        end: TokenPosition(12),
                    },
                    message: "after this `case`, an expression was expected",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0041_05.uc"),
        &ExpectedDiagnostic {
            headline: "missing expression after `case`",
            severity: Severity::Error,
            code: Some("P0041"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(11),
                    end: TokenPosition(11),
                },
                message: "expected expression before `:`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(8),
                        end: TokenPosition(8),
                    },
                    message: "after this `case`, an expression was expected",
                },
            ],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0042_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0042_01.uc",
        source: "switch(A) {\n    case *:\n}\n",
    },
    Fixture {
        label: "files/P0042_02.uc",
        source: "switch\n(A)\n{\n    case\n        =\n        :\n}\n",
    },
    Fixture {
        label: "files/P0042_03.uc",
        source: "switch(A) {\n    case &&:\n    default:\n}\n",
    },
    Fixture {
        label: "files/P0042_04.uc",
        source: "switch\n(\n    A\n)\n{\n    case\n        .\n        :\n    case 1:\n}\n",
    },
    Fixture {
        label: "files/P0042_05.uc",
        source: "switch(A) {\n    case ]:\n}\n",
    },
];

#[test]
fn check_p0042_fixtures() {
    let runs = run_fixtures(P0042_FIXTURES);

    assert_eq!(runs.get("files/P0042_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0042_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0042_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0042_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0042_05.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0042_01.uc"),
        &ExpectedDiagnostic {
            headline: "expected expression after `case`, found `*`",
            severity: Severity::Error,
            code: Some("P0042"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(10),
                    end: TokenPosition(10),
                },
                message: "unexpected `*`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0042_02.uc"),
        &ExpectedDiagnostic {
            headline: "expected expression after `case`, found `=`",
            severity: Severity::Error,
            code: Some("P0042"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(12),
                    end: TokenPosition(12),
                },
                message: "unexpected `=`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(9),
                        end: TokenPosition(9),
                    },
                    message: "after this `case`, an expression was expected",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0042_03.uc"),
        &ExpectedDiagnostic {
            headline: "expected expression after `case`, found `&&`",
            severity: Severity::Error,
            code: Some("P0042"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(10),
                    end: TokenPosition(10),
                },
                message: "unexpected `&&`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0042_04.uc"),
        &ExpectedDiagnostic {
            headline: "expected expression after `case`, found `.`",
            severity: Severity::Error,
            code: Some("P0042"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(15),
                    end: TokenPosition(15),
                },
                message: "unexpected `.`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(12),
                        end: TokenPosition(12),
                    },
                    message: "after this `case`, an expression was expected",
                },
            ],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0042_05.uc"),
        &ExpectedDiagnostic {
            headline: "expected expression after `case`, found `]`",
            severity: Severity::Error,
            code: Some("P0042"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(10),
                    end: TokenPosition(10),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0042_CASCADE_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0042_cascade_01.uc",
        source: "switch(A) {\n    case *\n    case 1:\n}\n",
    },
    Fixture {
        label: "files/P0042_cascade_02.uc",
        source: "switch\n(\n    A\n)\n{\n    case\n        =\n    default:\n}\n",
    },
];

#[test]
fn check_p0042_cascade_fixtures() {
    let runs = run_fixtures(P0042_CASCADE_FIXTURES);

    assert_eq!(runs.get("files/P0042_cascade_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0042_cascade_02.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0042_cascade_01.uc"),
        &ExpectedDiagnostic {
            headline: "expected expression after `case`, found `*`",
            severity: Severity::Error,
            code: Some("P0042"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(10),
                    end: TokenPosition(10),
                },
                message: "unexpected `*`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0042_cascade_02.uc"),
        &ExpectedDiagnostic {
            headline: "expected expression after `case`, found `=`",
            severity: Severity::Error,
            code: Some("P0042"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(15),
                    end: TokenPosition(15),
                },
                message: "unexpected `=`",
            }),
            secondary_labels: &[
                ExpectedLabel {
                    span: TokenSpan {
                        start: TokenPosition(12),
                        end: TokenPosition(12),
                    },
                    message: "after this `case`, an expression was expected",
                },
            ],
            help: None,
            notes: &[],
        },
    );
}
