import unittest

from h8536.pseudocode import PseudocodeOptions, generate_pseudocode, split_operands


class PseudocodeTest(unittest.TestCase):
    def test_split_operands_keeps_displacement_expression_together(self):
        self.assertEqual(split_operands("@(H'04,R6), R0"), ["@(H'04,R6)", "R0"])
        self.assertEqual(split_operands("{R0,R1}, @-SP"), ["{R0,R1}", "@-SP"])

    def test_generates_c_like_function_from_decompiler_json(self):
        payload = {
            "vectors": [{"address": 0, "name": "reset", "target": 0x0100, "target_label": "vec_reset_0100"}],
            "call_graph": {
                "nodes": [
                    {
                        "start": 0x0100,
                        "end": 0x0110,
                        "label": "vec_reset_0100",
                        "sources": ["reset"],
                        "instruction_count": 5,
                        "calls": [0x0200],
                    },
                    {
                        "start": 0x0200,
                        "end": 0x0200,
                        "label": "loc_0200",
                        "sources": [],
                        "instruction_count": 1,
                        "calls": [],
                    },
                ],
                "edges": [],
            },
            "instructions": [
                {
                    "address": 0x0100,
                    "text": "MOV:G.B #H'FF, @P1DDR",
                    "mnemonic": "MOV:G.B",
                    "operands": "#H'FF, @P1DDR",
                    "kind": "normal",
                    "targets": [],
                    "references": [{"address": 0xFE80, "name": "P1DDR", "region": "register_field"}],
                    "comment": "P1DDR = H'FF",
                    "peripheral_access": [
                        {
                            "register": "FRT2_FRC",
                            "direction": "write",
                            "size": "W",
                            "byte": "high",
                        },
                    ],
                },
                {
                    "address": 0x0105,
                    "text": "MOV:G.B #H'80, @RAMCR",
                    "mnemonic": "MOV:G.B",
                    "operands": "#H'80, @RAMCR",
                    "kind": "normal",
                    "targets": [],
                    "references": [{"address": 0xFF11, "name": "RAMCR", "region": "register_field"}],
                    "comment": "RAMCR = H'80",
                    "sci": {
                        "inferences": [
                            {"comment": "SCI1 async baud 31250 bps"},
                        ],
                    },
                },
                {
                    "address": 0x010A,
                    "text": "BNE loc_0110",
                    "mnemonic": "BNE",
                    "operands": "loc_0110",
                    "kind": "branch",
                    "targets": [0x0110],
                    "references": [],
                    "comment": "",
                },
                {
                    "address": 0x010C,
                    "text": "BSR loc_0200",
                    "mnemonic": "BSR",
                    "operands": "loc_0200",
                    "kind": "call",
                    "targets": [0x0200],
                    "references": [],
                    "comment": "",
                },
                {
                    "address": 0x0110,
                    "text": "RTS",
                    "mnemonic": "RTS",
                    "operands": "",
                    "kind": "return",
                    "targets": [],
                    "references": [],
                    "comment": "",
                },
                {
                    "address": 0x0200,
                    "text": "RTS",
                    "mnemonic": "RTS",
                    "operands": "",
                    "kind": "return",
                    "targets": [],
                    "references": [],
                    "comment": "",
                },
            ],
        }

        text = generate_pseudocode(payload, options=PseudocodeOptions(structured=False))

        self.assertIn("void vec_reset_0100(void)", text)
        self.assertIn("P1DDR = (uint8_t)(0xFF);", text)
        self.assertIn("RAMCR = (uint8_t)(0x80);", text)
        self.assertIn("SCI1 async baud 31250 bps", text)
        self.assertIn("FRT2_FRC W write high TEMP access", text)
        self.assertIn("if (!Z) goto loc_0110;", text)
        self.assertIn("loc_0200();", text)
        self.assertIn("loc_0110:", text)
        self.assertIn("return;", text)

    def test_zero_extends_byte_immediate_to_word_destination(self):
        payload = {
            "vectors": [{"address": 0, "name": "reset", "target": 0x4067, "target_label": "loc_4067"}],
            "call_graph": {
                "nodes": [
                    {
                        "start": 0x4067,
                        "end": 0x4067,
                        "label": "loc_4067",
                        "sources": ["reset"],
                        "instruction_count": 1,
                        "calls": [],
                    },
                ],
                "edges": [],
            },
            "instructions": [
                {
                    "address": 0x4067,
                    "text": "MOV:G.W #H'00, @(-H'0790,R2)",
                    "mnemonic": "MOV:G.W",
                    "operands": "#H'00, @(-H'0790,R2)",
                    "kind": "normal",
                    "targets": [],
                    "references": [],
                    "comment": "",
                },
            ],
        }

        text = generate_pseudocode(payload, options=PseudocodeOptions(structured=False))

        self.assertIn("zero_extend8_to16(0x00)", text)
        self.assertIn("byte immediate zero-extended into word destination", text)


if __name__ == "__main__":
    unittest.main()
