use super::*;

pub(super) const P0012_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0012_01.uc",
        source: "if ; DoThing();",
    },
    Fixture {
        label: "files/P0012_02.uc",
        source: "while\n\n;\nDoThing();",
    },
    Fixture {
        label: "files/P0012_03.uc",
        source: "do DoThing(); until ;",
    },
    Fixture {
        label: "files/P0012_04.uc",
        source: "if ) DoThing();",
    },
    Fixture {
        label: "files/P0012_05.uc",
        source: "do\n\nDoThing();\n\n\n\nuntil ;",
    },
    Fixture {
        label: "files/P0012_06.uc",
        source: "if \n\n{DoThing();}\n\n\n\n",
    },
];

#[test]
fn check_p0012_fixtures() {
    let runs = run_fixtures(P0012_FIXTURES);

    assert_eq!(runs.get("files/P0012_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0012_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0012_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0012_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0012_05.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0012_06.uc").unwrap().len(), 1);

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

    assert_diagnostic(
        &runs.get_any("files/P0012_02.uc"),
        &ExpectedDiagnostic {
            headline: "expected condition after `while`, found `;`",
            severity: Severity::Error,
            code: Some("P0012"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "unexpected `;`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "after this `while`, a condition was expected",
            }],
            help: None,
            notes: &[],
        },
    );

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

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

    assert_diagnostic(
        &runs.get_any("files/P0012_05.uc"),
        &ExpectedDiagnostic {
            headline: "expected condition after `until`, found `;`",
            severity: Severity::Error,
            code: Some("P0012"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(13),
                    end: TokenPosition(13),
                },
                message: "unexpected `;`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "`do` expression starts here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0012_06.uc"),
        &ExpectedDiagnostic {
            headline: "expected condition after `if`, found `{`",
            severity: Severity::Error,
            code: Some("P0012"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(4),
                    end: TokenPosition(4),
                },
                message: "body starts here, but the condition is missing",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "after this `if`, a condition was expected",
            }],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0013_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0013_01.uc",
        source: "if IsReady()",
    },
    Fixture {
        label: "files/P0013_02.uc",
        source: "while\n\nIsReady() : ",
    },
    Fixture {
        label: "files/P0013_03.uc",
        source: "for (I = 0; I < Count; ++I)\n\n",
    },
    Fixture {
        label: "files/P0013_04.uc",
        source: "if IsReady()\n    DoThing();\nelse\n\n\n\n:\n\n\n",
    },
];

#[test]
fn check_p0013_fixtures() {
    let runs = run_fixtures(P0013_FIXTURES);

    assert_eq!(runs.get("files/P0013_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0013_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0013_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0013_04.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0013_01.uc"),
        &ExpectedDiagnostic {
            headline: "expected body for `if`, found end of file",
            severity: Severity::Error,
            code: Some("P0013"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "reached end of file here",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0013_02.uc"),
        &ExpectedDiagnostic {
            headline: "expected body for `while`, found `:`",
            severity: Severity::Error,
            code: Some("P0013"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "unexpected `:`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "after this `)`, a body was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0013_03.uc"),
        &ExpectedDiagnostic {
            headline: "expected body for `for`, found end of file",
            severity: Severity::Error,
            code: Some("P0013"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(22),
                    end: TokenPosition(22),
                },
                message: "reached end of file here",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(19),
                    end: TokenPosition(19),
                },
                message: "after this `)`, a body was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0013_04.uc"),
        &ExpectedDiagnostic {
            headline: "expected body for `else`, found `:`",
            severity: Severity::Error,
            code: Some("P0013"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(17),
                    end: TokenPosition(17),
                },
                message: "unexpected `:`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(12),
                    end: TokenPosition(12),
                },
                message: "after this `else`, a body was expected",
            }],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0014_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0014_01.uc",
        source: "do DoThing();",
    },
    Fixture {
        label: "files/P0014_02.uc",
        source: "do\n    DoThing();\n",
    },
    Fixture {
        label: "files/P0014_03.uc",
        source: "do\n\n;\n\n:\n",
    },
    Fixture {
        label: "files/P0014_04.uc",
        source: "do\n{\n    DoThing();\n}\n\n\n:\n",
    },
];

#[test]
fn check_p0014_fixtures() {
    let runs = run_fixtures(P0014_FIXTURES);

    assert_eq!(runs.get("files/P0014_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0014_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0014_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0014_04.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0014_01.uc"),
        &ExpectedDiagnostic {
            headline: "missing `until` after `do` body",
            severity: Severity::Error,
            code: Some("P0014"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(6),
                    end: TokenPosition(6),
                },
                message: "expected `until` before end of file",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0014_02.uc"),
        &ExpectedDiagnostic {
            headline: "missing `until` after `do` body",
            severity: Severity::Error,
            code: Some("P0014"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(8),
                },
                message: "expected `until` before end of file",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "`do` expression starts here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0014_03.uc"),
        &ExpectedDiagnostic {
            headline: "missing `until` after `do` body",
            severity: Severity::Error,
            code: Some("P0014"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(6),
                },
                message: "expected `until` before `:`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "`do` expression starts here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0014_04.uc"),
        &ExpectedDiagnostic {
            headline: "missing `until` after `do` body",
            severity: Severity::Error,
            code: Some("P0014"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(14),
                },
                message: "expected `until` before `:`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "`do` expression starts here",
            }],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0015_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0015_01.uc",
        source: "foreach",
    },
    Fixture {
        label: "files/P0015_02.uc",
        source: "foreach ;",
    },
    Fixture {
        label: "files/P0015_03.uc",
        source: "foreach }",
    },
    Fixture {
        label: "files/P0015_04.uc",
        source: "foreach\n\n)\n    P.Destroy();\n",
    },
    Fixture {
        label: "files/P0015_05.uc",
        source: "foreach\n{\n    Log(A);\n}\n",
    },
];

#[test]
fn check_p0015_fixtures() {
    let runs = run_fixtures(P0015_FIXTURES);

    assert_eq!(runs.get("files/P0015_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0015_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0015_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0015_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0015_05.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0015_01.uc"),
        &ExpectedDiagnostic {
            headline: "expected iterator expression after `foreach`, found end of file",
            severity: Severity::Error,
            code: Some("P0015"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(1),
                    end: TokenPosition(1),
                },
                message: "reached end of file here",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

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

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

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

    assert_diagnostic(
        &runs.get_any("files/P0015_05.uc"),
        &ExpectedDiagnostic {
            headline: "expected iterator expression after `foreach`, found `{`",
            severity: Severity::Error,
            code: Some("P0015"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(2),
                    end: TokenPosition(2),
                },
                message: "body starts here, but the iterator expression is missing",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "after this `foreach`, an iterator expression was expected",
            }],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const FOR_HEADER_FIXTURES: &[Fixture] = &[
    // P0016: invalid initializer start after `for (`
    Fixture {
        label: "files/P0016_01.uc",
        source: "for\n(] ; )",
    },
    Fixture {
        label: "files/P0016_02.uc",
        source: "for (\n    ]\n    ;\n)\n    Body();\n",
    },
    Fixture {
        label: "files/P0016_03.uc",
        source: "for (\n    }\n    ;\n)\n",
    },
    Fixture {
        label: "files/P0016_06.uc",
        source: "for (\n    ]\n\n\n    ; Step)\n",
    },

    // P0017: initializer parsed, but first `;` is missing
    Fixture {
        label: "files/P0017_01.uc",
        source: "for (Init ] ; )",
    },
    Fixture {
        label: "files/P0017_02.uc",
        source: "for (Init\n    ]\n    ;\n)\n",
    },
    Fixture {
        label: "files/P0017_04.uc",
        source: "for (Init {\n    Body();\n}; )\n",
    },
    Fixture {
        label: "files/P0017_05.uc",
        source: "for (Init",
    },

    // P0018: invalid condition start after first `;`
    Fixture {
        label: "files/P0018_01.uc",
        source: "for \n\n    (; ] ; )",
    },
    Fixture {
        label: "files/P0018_02.uc",
        source: "for (;\n    ]\n    ;\n)\n    Body();\n",
    },
    Fixture {
        label: "files/P0018_03.uc",
        source: "for (;\n    }\n    ;\n)\n",
    },
    Fixture {
        label: "files/P0018_06.uc",
        source: "for (;",
    },

    // P0019: condition parsed, but second `;` is missing
    Fixture {
        label: "files/P0019_01.uc",
        source: "for (; bCondition )",
    },
    Fixture {
        label: "files/P0019_02.uc",
        source: "for (; bCondition\n)\n    Body();\n",
    },
    Fixture {
        label: "files/P0019_03.uc",
        source: "for (; bCondition ] ; )",
    },
    Fixture {
        label: "files/P0019_04.uc",
        source: "for (; bCondition\n{\n    Body();\n}\n;\n)\n",
    },
    Fixture {
        label: "files/P0019_06.uc",
        source: "for (; bCondition",
    },
    Fixture {
        label: "files/P0019_07.uc",
        source: "for (; bCondition Step)",
    },

    // P0020: invalid step start after second `;`
    Fixture {
        label: "files/P0020_01.uc",
        source: "for (;;;)",
    },
    Fixture {
        label: "files/P0020_02.uc",
        source: "for (;;\n    ;\n)\n",
    },
    Fixture {
        label: "files/P0020_03.uc",
        source: "for (;; ])",
    },
    Fixture {
        label: "files/P0020_04.uc",
        source: "for (;;\n    }\n)\n",
    },
    Fixture {
        label: "files/P0020_08.uc",
        source: "for (;;\n    ]\n",
    },

    // P0021: missing `)` to close `for` header
    Fixture {
        label: "files/P0021_01.uc",
        source: "for (;;",
    },
    Fixture {
        label: "files/P0021_02.uc",
        source: "for (;; Step",
    },
    Fixture {
        label: "files/P0021_03.uc",
        source: "for (;; Step;\n    Body();\n",
    },
    Fixture {
        label: "files/P0021_05.uc",
        source: "for (Init; bCondition; Step\n{\n    Body();\n}\n",
    },
    Fixture {
        label: "files/P0021_09.uc",
        source: "for\n(Init;\n    bCondition;\n    Step\n]\n",
    },
];

#[test]
fn check_p0016_for_header_fixture_counts() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_eq!(runs.get("files/P0016_01.uc").unwrap().len(), 3);
    assert_eq!(runs.get("files/P0016_02.uc").unwrap().len(), 2);
    assert_eq!(runs.get("files/P0016_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0016_06.uc").unwrap().len(), 3);
}

#[test]
fn check_p0017_for_header_fixture_counts() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_eq!(runs.get("files/P0017_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0017_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0017_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0017_05.uc").unwrap().len(), 1);
}

#[test]
fn check_p0018_for_header_fixture_counts() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_eq!(runs.get("files/P0018_01.uc").unwrap().len(), 2);
    assert_eq!(runs.get("files/P0018_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0018_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0018_06.uc").unwrap().len(), 1);
}

#[test]
fn check_p0019_for_header_fixture_counts() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_eq!(runs.get("files/P0019_01.uc").unwrap().len(), 2);
    assert_eq!(runs.get("files/P0019_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0019_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0019_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0019_06.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0019_07.uc").unwrap().len(), 1);
}

#[test]
fn check_p0020_for_header_fixture_counts() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_eq!(runs.get("files/P0020_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0020_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0020_03.uc").unwrap().len(), 2);
    assert_eq!(runs.get("files/P0020_04.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0020_08.uc").unwrap().len(), 1);
}

#[test]
fn check_p0021_for_header_fixture_counts() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_eq!(runs.get("files/P0021_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0021_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0021_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0021_05.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0021_09.uc").unwrap().len(), 1);
}

#[test]
fn check_p0016_for_header_fixtures() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_diagnostic(
        &runs.get_by_code("files/P0016_01.uc", "P0016"),
        &ExpectedDiagnostic {
            headline: "expected initializer expression or `;` after `(` in `for` header, found `]`",
            severity: Severity::Error,
            code: Some("P0016"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "`for` loop starts here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0016_02.uc", "P0016"),
        &ExpectedDiagnostic {
            headline: "expected initializer expression or `;` after `(` in `for` header, found `]`",
            severity: Severity::Error,
            code: Some("P0016"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(2),
                    end: TokenPosition(2),
                },
                message: "after this `(`, an initializer expression or `;` was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0016_03.uc", "P0016"),
        &ExpectedDiagnostic {
            headline: "expected initializer expression or `;` after `(` in `for` header, found `}`",
            severity: Severity::Error,
            code: Some("P0016"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "unexpected `}`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(2),
                    end: TokenPosition(2),
                },
                message: "after this `(`, an initializer expression or `;` was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0016_06.uc", "P0016"),
        &ExpectedDiagnostic {
            headline: "expected initializer expression or `;` after `(` in `for` header, found `]`",
            severity: Severity::Error,
            code: Some("P0016"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(2),
                    end: TokenPosition(2),
                },
                message: "after this `(`, an initializer expression or `;` was expected",
            }],
            help: None,
            notes: &[],
        },
    );
}

#[test]
fn check_p0017_for_header_fixtures() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_diagnostic(
        &runs.get_by_code("files/P0017_01.uc", "P0017"),
        &ExpectedDiagnostic {
            headline: "missing `;` after initializer in `for` header",
            severity: Severity::Error,
            code: Some("P0017"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "expected `;` before `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "initializer ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0017_02.uc", "P0017"),
        &ExpectedDiagnostic {
            headline: "missing `;` after initializer in `for` header",
            severity: Severity::Error,
            code: Some("P0017"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(6),
                    end: TokenPosition(6),
                },
                message: "expected `;` before `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "initializer ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0017_04.uc", "P0017"),
        &ExpectedDiagnostic {
            headline: "missing `;` after initializer in `for` header",
            severity: Severity::Error,
            code: Some("P0017"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "expected `;` before `{`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "initializer ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0017_05.uc", "P0017"),
        &ExpectedDiagnostic {
            headline: "missing `;` after initializer in `for` header",
            severity: Severity::Error,
            code: Some("P0017"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(4),
                    end: TokenPosition(4),
                },
                message: "expected `;` before end of file",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "initializer ends here",
            }],
            help: None,
            notes: &[],
        },
    );
}

#[test]
fn check_p0018_for_header_fixtures() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_diagnostic(
        &runs.get_by_code("files/P0016_01.uc", "P0018"),
        &ExpectedDiagnostic {
            headline: "expected condition expression or second `;` in `for` header, found `)`",
            severity: Severity::Error,
            code: Some("P0018"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "unexpected `)`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "`for` loop starts here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0016_02.uc", "P0018"),
        &ExpectedDiagnostic {
            headline: "expected condition expression or second `;` in `for` header, found `)`",
            severity: Severity::Error,
            code: Some("P0018"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(10),
                    end: TokenPosition(10),
                },
                message: "unexpected `)`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(8),
                    end: TokenPosition(8),
                },
                message: "after this `;`, a condition expression or another `;` was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0018_01.uc", "P0018"),
        &ExpectedDiagnostic {
            headline: "expected condition expression or second `;` in `for` header, found `]`",
            severity: Severity::Error,
            code: Some("P0018"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(8),
                    end: TokenPosition(8),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "`for` loop starts here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0018_02.uc", "P0018"),
        &ExpectedDiagnostic {
            headline: "expected condition expression or second `;` in `for` header, found `]`",
            severity: Severity::Error,
            code: Some("P0018"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(6),
                    end: TokenPosition(6),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "after this `;`, a condition expression or another `;` was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0018_03.uc", "P0018"),
        &ExpectedDiagnostic {
            headline: "expected condition expression or second `;` in `for` header, found `}`",
            severity: Severity::Error,
            code: Some("P0018"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(6),
                    end: TokenPosition(6),
                },
                message: "unexpected `}`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "after this `;`, a condition expression or another `;` was expected",
            }],
            help: None,
            notes: &[],
        },
    );
}

#[test]
fn check_p0019_for_header_fixtures() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_diagnostic(
        &runs.get_by_code("files/P0016_06.uc", "P0019"),
        &ExpectedDiagnostic {
            headline: "missing `;` after condition in `for` header",
            severity: Severity::Error,
            code: Some("P0019"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(13),
                    end: TokenPosition(13),
                },
                message: "expected `;` before `)`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(12),
                    end: TokenPosition(12),
                },
                message: "condition ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0018_06.uc", "P0019"),
        &ExpectedDiagnostic {
            headline: "missing second `;` in `for` header",
            severity: Severity::Error,
            code: Some("P0019"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(4),
                    end: TokenPosition(4),
                },
                message: "expected second `;` before end of file",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0019_01.uc", "P0019"),
        &ExpectedDiagnostic {
            headline: "missing `;` after condition in `for` header",
            severity: Severity::Error,
            code: Some("P0019"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "expected `;` before `)`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "condition ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0019_02.uc", "P0019"),
        &ExpectedDiagnostic {
            headline: "missing `;` after condition in `for` header",
            severity: Severity::Error,
            code: Some("P0019"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "expected `;` before `)`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "condition ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0019_03.uc", "P0019"),
        &ExpectedDiagnostic {
            headline: "missing `;` after condition in `for` header",
            severity: Severity::Error,
            code: Some("P0019"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "expected `;` before `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "condition ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0019_04.uc", "P0019"),
        &ExpectedDiagnostic {
            headline: "missing `;` after condition in `for` header",
            severity: Severity::Error,
            code: Some("P0019"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "expected `;` before `{`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "condition ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0019_06.uc", "P0019"),
        &ExpectedDiagnostic {
            headline: "missing `;` after condition in `for` header",
            severity: Severity::Error,
            code: Some("P0019"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(6),
                    end: TokenPosition(6),
                },
                message: "expected `;` before end of file",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "condition ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0019_07.uc", "P0019"),
        &ExpectedDiagnostic {
            headline: "missing `;` after condition in `for` header",
            severity: Severity::Error,
            code: Some("P0019"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "expected `;` before `Step`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "condition ends here",
            }],
            help: None,
            notes: &[],
        },
    );
}

#[test]
fn check_p0020_for_header_fixtures() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_diagnostic(
        &runs.get_by_code("files/P0020_01.uc", "P0020"),
        &ExpectedDiagnostic {
            headline: "unexpected third `;` in `for` header",
            severity: Severity::Error,
            code: Some("P0020"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(5),
                    end: TokenPosition(5),
                },
                message: "expected step expression or `)` after the second `;`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0020_02.uc", "P0020"),
        &ExpectedDiagnostic {
            headline: "unexpected third `;` in `for` header",
            severity: Severity::Error,
            code: Some("P0020"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "expected step expression or `)` after the second `;`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(4),
                    end: TokenPosition(4),
                },
                message: "after this `;`, a step expression or `)` was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0020_03.uc", "P0020"),
        &ExpectedDiagnostic {
            headline: "expected step expression or `)` after the second `;` in `for` header, found `]`",
            severity: Severity::Error,
            code: Some("P0020"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(6),
                    end: TokenPosition(6),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0020_04.uc", "P0020"),
        &ExpectedDiagnostic {
            headline: "expected step expression or `)` after the second `;` in `for` header, found `}`",
            severity: Severity::Error,
            code: Some("P0020"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "unexpected `}`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(4),
                    end: TokenPosition(4),
                },
                message: "after this `;`, a step expression or `)` was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0020_08.uc", "P0020"),
        &ExpectedDiagnostic {
            headline: "expected step expression or `)` after the second `;` in `for` header, found `]`",
            severity: Severity::Error,
            code: Some("P0020"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(4),
                    end: TokenPosition(4),
                },
                message: "after this `;`, a step expression or `)` was expected",
            }],
            help: None,
            notes: &[],
        },
    );
}

#[test]
fn check_p0021_for_header_fixtures() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

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

    assert_diagnostic(
        &runs.get_by_code("files/P0021_02.uc", "P0021"),
        &ExpectedDiagnostic {
            headline: "missing `)` to close `for` header",
            severity: Severity::Error,
            code: Some("P0021"),
            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_by_code("files/P0021_03.uc", "P0021"),
        &ExpectedDiagnostic {
            headline: "missing `)` to close `for` header",
            severity: Severity::Error,
            code: Some("P0021"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(7),
                    end: TokenPosition(7),
                },
                message: "expected `)` before `;`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0021_05.uc", "P0021"),
        &ExpectedDiagnostic {
            headline: "missing `)` to close `for` header",
            severity: Severity::Error,
            code: Some("P0021"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(2),
                    end: TokenPosition(11),
                },
                message: "expected `)` before `{`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(2),
                    end: TokenPosition(2),
                },
                message: "`for` header starts here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0021_09.uc", "P0021"),
        &ExpectedDiagnostic {
            headline: "missing `)` to close `for` header",
            severity: Severity::Error,
            code: Some("P0021"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(2),
                    end: TokenPosition(13),
                },
                message: "expected `)` before `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(2),
                    end: TokenPosition(2),
                },
                message: "`for` header starts here",
            }],
            help: None,
            notes: &[],
        },
    );
}

#[test]
fn check_p0013_for_header_body_recovery_fixtures() {
    let runs = run_fixtures(FOR_HEADER_FIXTURES);

    assert_diagnostic(
        &runs.get_by_code("files/P0016_01.uc", "P0013"),
        &ExpectedDiagnostic {
            headline: "expected body for `for`, found end of file",
            severity: Severity::Error,
            code: Some("P0013"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(8),
                    end: TokenPosition(8),
                },
                message: "reached end of file here",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0016_06.uc", "P0013"),
        &ExpectedDiagnostic {
            headline: "expected body for `for`, found end of file",
            severity: Severity::Error,
            code: Some("P0013"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(15),
                    end: TokenPosition(15),
                },
                message: "reached end of file here",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0018_01.uc", "P0013"),
        &ExpectedDiagnostic {
            headline: "expected body for `for`, found end of file",
            severity: Severity::Error,
            code: Some("P0013"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(13),
                    end: TokenPosition(13),
                },
                message: "reached end of file here",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0019_01.uc", "P0013"),
        &ExpectedDiagnostic {
            headline: "expected body for `for`, found end of file",
            severity: Severity::Error,
            code: Some("P0013"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(8),
                    end: TokenPosition(8),
                },
                message: "reached end of file here",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P0020_03.uc", "P0013"),
        &ExpectedDiagnostic {
            headline: "expected body for `for`, found end of file",
            severity: Severity::Error,
            code: Some("P0013"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(8),
                    end: TokenPosition(8),
                },
                message: "reached end of file here",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0022_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0022_01.uc",
        source: "return ] ;",
    },
    Fixture {
        label: "files/P0022_02.uc",
        source: "return\n    ]\n;\n",
    },
    Fixture {
        label: "files/P0022_03.uc",
        source: "return\n}\n",
    },
];

#[test]
fn check_p0022_fixtures() {
    let runs = run_fixtures(P0022_FIXTURES);

    assert_eq!(runs.get("files/P0022_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0022_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0022_03.uc").unwrap().len(), 1);

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

    assert_diagnostic(
        &runs.get_any("files/P0022_02.uc"),
        &ExpectedDiagnostic {
            headline: "expected return value expression or `;` after `return`, found `]`",
            severity: Severity::Error,
            code: Some("P0022"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "after this `return`, a value expression or `;` was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0022_03.uc"),
        &ExpectedDiagnostic {
            headline: "expected return value expression or `;` after `return`, found `}`",
            severity: Severity::Error,
            code: Some("P0022"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(2),
                    end: TokenPosition(2),
                },
                message: "unexpected `}`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "after this `return`, a value expression or `;` was expected",
            }],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0023_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0023_01.uc",
        source: "break ] ;",
    },
    Fixture {
        label: "files/P0023_02.uc",
        source: "break\n \n\n\n\n   ]\n;\n",
    },
    Fixture {
        label: "files/P0023_03.uc",
        source: "break\n}\n",
    },
];

#[test]
fn check_p0023_fixtures() {
    let runs = run_fixtures(P0023_FIXTURES);

    assert_eq!(runs.get("files/P0023_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0023_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0023_03.uc").unwrap().len(), 1);

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

    assert_diagnostic(
        &runs.get_any("files/P0023_02.uc"),
        &ExpectedDiagnostic {
            headline: "expected break value expression or `;` after `break`, found `]`",
            severity: Severity::Error,
            code: Some("P0023"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(8),
                    end: TokenPosition(8),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "after this `break`, a value expression or `;` was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0023_03.uc"),
        &ExpectedDiagnostic {
            headline: "expected break value expression or `;` after `break`, found `}`",
            severity: Severity::Error,
            code: Some("P0023"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(2),
                    end: TokenPosition(2),
                },
                message: "unexpected `}`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "after this `break`, a value expression or `;` was expected",
            }],
            help: None,
            notes: &[],
        },
    );
}

pub(super) const P0024_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0024_01.uc",
        source: "goto;",
    },
    Fixture {
        label: "files/P0024_02.uc",
        source: "goto\n    ;\n",
    },
    Fixture {
        label: "files/P0024_03.uc",
        source: "goto\n    ]\n;\n",
    },
    Fixture {
        label: "files/P0024_04.uc",
        source: "goto",
    },
];

#[test]
fn check_p0024_fixtures() {
    let runs = run_fixtures(P0024_FIXTURES);

    assert_eq!(runs.get("files/P0024_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0024_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0024_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0024_04.uc").unwrap().len(), 1);

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

    assert_diagnostic(
        &runs.get_any("files/P0024_02.uc"),
        &ExpectedDiagnostic {
            headline: "expected label after `goto`, found `;`",
            severity: Severity::Error,
            code: Some("P0024"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "unexpected `;`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "after this `goto`, a label was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0024_03.uc"),
        &ExpectedDiagnostic {
            headline: "expected label after `goto`, found `]`",
            severity: Severity::Error,
            code: Some("P0024"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(3),
                    end: TokenPosition(3),
                },
                message: "unexpected `]`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(0),
                    end: TokenPosition(0),
                },
                message: "after this `goto`, a label was expected",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0024_04.uc"),
        &ExpectedDiagnostic {
            headline: "expected label after `goto`, found end of file",
            severity: Severity::Error,
            code: Some("P0024"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(1),
                    end: TokenPosition(1),
                },
                message: "reached end of file here",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );
}