use super::*;

pub(super) const P0025_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0025_01.uc",
        source: "{\n    local int Count;\n    Count = Count + 1 UpdateHud();\n    DrawHud(CanvasRef);\n}\n",
    },
    Fixture {
        label: "files/P0025_02.uc",
        source: "{\n    local float XL;\n    C.TextSize(LevelTitle, XL, YL)\n    C.SetPos(0, 0);\n    C.DrawText(LevelTitle);\n}\n",
    },
    Fixture {
        label: "files/P0025_03.uc",
        source: "{\n    local bool bReady;\n    bReady = CheckReady()\n    if (bReady) { StartMatch(); }\n    NotifyReady();\n}\n",
    },
    Fixture {
        label: "files/P0025_04.uc",
        source: "{\n    local int I;\n    Scores[I] = Scores[I] + 1\n    I++;\n    RefreshScores();\n}\n",
    },
];

pub(super) const P0026_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0026_01.uc",
        source: "{\n    local int Count;\n    Count = 0;\n    Count++;\n    UpdateHud();\n",
    },
    Fixture {
        label: "files/P0026_02.uc",
        source: "{\n    local bool bReady;\n    bReady = CheckReady();\n    if (bReady) { StartMatch(); }\n    NotifyReady();\n",
    },
    Fixture {
        label: "files/P0026_03.uc",
        source: "{    local float XL;    do { C.TextSize(LevelTitle, XL, YL); } until (XL < C.ClipX)    C.SetPos(0, 0);    C.DrawText(LevelTitle);",
    },
    Fixture {
        label: "files/P0026_04.uc",
        source: "{\n    local int Count;\n    Count = Count + 1;\n    UpdateHud();\n    Count\n",
    },
];

pub(super) const P0025_P0026_MIXED_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P_mixed_01.uc",
        source: "{    local int Count;    Count = Count + 1    UpdateHud();    DrawHud(CanvasRef);",
    },
    Fixture {
        label: "files/P_mixed_02.uc",
        source: "{\n    local bool bReady;\n    bReady = CheckReady()\n    if (bReady) { StartMatch(); }\n    NotifyReady();\n",
    },
];

#[test]
fn check_p0025_fixtures() {
    let runs = run_fixtures(P0025_FIXTURES);

    assert_eq!(runs.get("files/P0025_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0025_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0025_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0025_04.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0025_01.uc"),
        &ExpectedDiagnostic {
            headline: "missing `;` after expression statement",
            severity: Severity::Error,
            code: Some("P0025"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(21),
                    end: TokenPosition(21),
                },
                message: "expected `;` before `UpdateHud`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(11),
                    end: TokenPosition(19),
                },
                message: "expression statement",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0025_02.uc"),
        &ExpectedDiagnostic {
            headline: "missing `;` after expression statement",
            severity: Severity::Error,
            code: Some("P0025"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(25),
                    end: TokenPosition(25),
                },
                message: "expected `;` before `C`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(22),
                    end: TokenPosition(22),
                },
                message: "expression statement ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0025_03.uc"),
        &ExpectedDiagnostic {
            headline: "missing `;` after expression statement",
            severity: Severity::Error,
            code: Some("P0025"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(20),
                    end: TokenPosition(20),
                },
                message: "expected `;` before `if`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(17),
                    end: TokenPosition(17),
                },
                message: "expression statement ends here",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0025_04.uc"),
        &ExpectedDiagnostic {
            headline: "missing `;` after expression statement",
            severity: Severity::Error,
            code: Some("P0025"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(28),
                    end: TokenPosition(28),
                },
                message: "expected `;` before `I`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(25),
                    end: TokenPosition(25),
                },
                message: "expression statement ends here",
            }],
            help: None,
            notes: &[],
        },
    );
}

#[test]
fn check_p0026_fixtures() {
    let runs = run_fixtures(P0026_FIXTURES);

    assert_eq!(runs.get("files/P0026_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0026_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0026_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0026_04.uc").unwrap().len(), 1);

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

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

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

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

#[test]
fn check_p0025_mixed_fixtures() {
    let runs = run_fixtures(P0025_P0026_MIXED_FIXTURES);

    assert_eq!(runs.get("files/P_mixed_01.uc").unwrap().len(), 2);
    assert_eq!(runs.get("files/P_mixed_02.uc").unwrap().len(), 2);

    assert_diagnostic(
        &runs.get_by_code("files/P_mixed_01.uc", "P0025"),
        &ExpectedDiagnostic {
            headline: "missing `;` after expression statement",
            severity: Severity::Error,
            code: Some("P0025"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(19),
                    end: TokenPosition(19),
                },
                message: "expected `;` before `UpdateHud`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(9),
                    end: TokenPosition(17),
                },
                message: "expression statement",
            }],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_by_code("files/P_mixed_02.uc", "P0025"),
        &ExpectedDiagnostic {
            headline: "missing `;` after expression statement",
            severity: Severity::Error,
            code: Some("P0025"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(20),
                    end: TokenPosition(20),
                },
                message: "expected `;` before `if`",
            }),
            secondary_labels: &[ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(17),
                    end: TokenPosition(17),
                },
                message: "expression statement ends here",
            }],
            help: None,
            notes: &[],
        },
    );
}

#[test]
fn check_p0026_mixed_fixtures() {
    let runs = run_fixtures(P0025_P0026_MIXED_FIXTURES);

    assert_eq!(runs.get("files/P_mixed_01.uc").unwrap().len(), 2);
    assert_eq!(runs.get("files/P_mixed_02.uc").unwrap().len(), 2);

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

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

pub(super) const P0027_FIXTURES: &[Fixture] = &[
    Fixture {
        label: "files/P0027_01.uc",
        source: "{\n    local bool bReady;\n    bReady = CheckReady();\n    else { StartMatch(); }\n    NotifyReady();\n}\n",
    },
    Fixture {
        label: "files/P0027_02.uc",
        source: "{    local int Count;    Count = 3;    case 3:        Count++;    UpdateHud();}",
    },
    Fixture {
        label: "files/P0027_03.uc",
        source: "{\n    local bool bDone;\n    bDone = false;\n    until (bDone)\n    TickWork();\n}\n",
    },
    Fixture {
        label: "files/P0027_04.uc",
        source: "{\n    local int Count;\n    Count = 0;\n    #exec TEXTURE IMPORT NAME=Bad FILE=Bad.bmp\n    Count++;\n}\n",
    },
];

#[test]
fn check_p0027_fixtures() {
    let runs = run_fixtures(P0027_FIXTURES);

    assert_eq!(runs.get("files/P0027_01.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0027_02.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0027_03.uc").unwrap().len(), 1);
    assert_eq!(runs.get("files/P0027_04.uc").unwrap().len(), 1);

    assert_diagnostic(
        &runs.get_any("files/P0027_01.uc"),
        &ExpectedDiagnostic {
            headline: "expected statement or expression, found `else`",
            severity: Severity::Error,
            code: Some("P0027"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(21),
                    end: TokenPosition(21),
                },
                message: "unexpected `else`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

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

    assert_diagnostic(
        &runs.get_any("files/P0027_03.uc"),
        &ExpectedDiagnostic {
            headline: "expected statement or expression, found `until`",
            severity: Severity::Error,
            code: Some("P0027"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(19),
                    end: TokenPosition(19),
                },
                message: "unexpected `until`",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );

    assert_diagnostic(
        &runs.get_any("files/P0027_04.uc"),
        &ExpectedDiagnostic {
            headline: "expected statement or expression, found `#exec` directive",
            severity: Severity::Error,
            code: Some("P0027"),
            primary_label: Some(ExpectedLabel {
                span: TokenSpan {
                    start: TokenPosition(19),
                    end: TokenPosition(19),
                },
                message: "`#exec` directives are not allowed in a statement block",
            }),
            secondary_labels: &[],
            help: None,
            notes: &[],
        },
    );
}