package p.studio.compiler.workspaces.stages;

import org.junit.jupiter.api.Test;
import p.studio.compiler.backend.bytecode.BytecodeModule;
import p.studio.compiler.messages.BuilderPipelineConfig;
import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.utilities.logs.LogAggregator;
import p.studio.utilities.structures.ReadOnlyList;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

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

class VerifyBytecodePipelineStageTest {

    @Test
    void runMustFailWhenBytecodeModuleIsMissing() {
        final var ctx = BuilderPipelineContext.fromConfig(new BuilderPipelineConfig(false, "."));
        final var stage = new VerifyBytecodePipelineStage();

        final var issues = stage.run(ctx, LogAggregator.empty());
        final var firstIssue = issues.asCollection().iterator().next();

        assertTrue(issues.hasErrors());
        assertEquals("BACKEND_VERIFY_PRELOAD", firstIssue.getPhase());
        assertEquals("MARSHAL_FORMAT_STAGE_INPUT_MISSING", firstIssue.getCode());
    }

    @Test
    void runMustRejectRawSyscallInPreload() {
        final var ctx = BuilderPipelineContext.fromConfig(new BuilderPipelineConfig(false, "."));
        ctx.bytecodeModule = new BytecodeModule(
                0,
                ReadOnlyList.empty(),
                ReadOnlyList.from(new BytecodeModule.FunctionMeta(0, 6, 0, 0, 0, 1)),
                codeRawSyscall(0x1001),
                null,
                ReadOnlyList.empty(),
                ReadOnlyList.empty());

        final var issues = new VerifyBytecodePipelineStage().run(ctx, LogAggregator.empty());
        final var firstIssue = issues.asCollection().iterator().next();

        assertTrue(issues.hasErrors());
        assertEquals("MARSHAL_LINKAGE_RAW_SYSCALL_IN_PRELOAD", firstIssue.getCode());
    }

    private byte[] codeRawSyscall(final int index) {
        final var out = ByteBuffer.allocate(6).order(ByteOrder.LITTLE_ENDIAN);
        out.putShort((short) 0x70);
        out.putInt(index);
        return out.array();
    }
}
