package p.studio.compiler.pbs.semantics;

import org.junit.jupiter.api.Test;
import p.studio.compiler.pbs.PbsFrontendCompiler;
import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.compiler.source.identifiers.FileId;

import static org.junit.jupiter.api.Assertions.assertTrue;

class PbsSemanticsOptionalResultTest {

    @Test
    void shouldValidateOptionalAndResultFlowRules() {
        final var source = """
                declare error ErrA { Fail; }
                declare error ErrB { Oops; }

                fn make() -> result<ErrA> int { return ok(1); }

                fn badOptional() -> int {
                  let x = none;
                  let y: int = 1 else 2;
                  return x + y;
                }

                fn badResult() -> result<ErrB> int {
                  let a: int = make()!;
                  let b: int = handle make() { ErrA.Fail -> ErrA.Fail };
                  return ok(a + b);
                }
                """;
        final var diagnostics = DiagnosticSink.empty();

        new PbsFrontendCompiler().compileFile(new FileId(0), source, diagnostics);

        assertTrue(diagnostics.stream().anyMatch(d ->
                d.getCode().equals(PbsSemanticsErrors.E_SEM_NONE_WITHOUT_EXPECTED_OPTIONAL.name())));
        assertTrue(diagnostics.stream().anyMatch(d ->
                d.getCode().equals(PbsSemanticsErrors.E_SEM_ELSE_NON_OPTIONAL_LEFT.name())));
        assertTrue(diagnostics.stream().anyMatch(d ->
                d.getCode().equals(PbsSemanticsErrors.E_SEM_RESULT_PROPAGATE_ERROR_MISMATCH.name())));
        assertTrue(diagnostics.stream().anyMatch(d ->
                d.getCode().equals(PbsSemanticsErrors.E_SEM_HANDLE_ERROR_MISMATCH.name())));
    }
}
