"""Tests IR interpreter handling of basic floating point operations (fadd, fsub, etc)."""

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class FPEvalTestCase(TestBase):
    def setUp(self):
        # Call super's setUp().
        TestBase.setUp(self)
        self.jit_opts = lldb.SBExpressionOptions()
        self.jit_opts.SetAllowJIT(True)
        self.no_jit_opts = lldb.SBExpressionOptions()
        self.no_jit_opts.SetAllowJIT(False)
        # Find the line number to break inside main().
        self.line = line_number("main.c", "// Set break point at this line.")

    def test(self):
        """Test floating point expressions while jitter is disabled."""
        self.build()
        exe = self.getBuildArtifact("a.out")
        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)

        # Break inside the main.
        lldbutil.run_break_set_by_file_and_line(
            self, "main.c", self.line, num_expected_locations=1, loc_exact=True
        )

        value = self.frame().EvaluateExpression("a + b", self.no_jit_opts)

        self.runCmd("run", RUN_SUCCEEDED)
        # test double
        self.expect(
            "expr --allow-jit false  -- a + b",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["double", "44"],
        )
        self.expect(
            "expr --allow-jit false  -- a - b",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["double", "40"],
        )
        self.expect(
            "expr --allow-jit false  -- a / b",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["double", "21"],
        )
        self.expect(
            "expr --allow-jit false  -- a * b",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["double", "84"],
        )
        self.expect(
            "expr --allow-jit false  -- a + 2",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["double", "44"],
        )
        self.expect(
            "expr --allow-jit false  -- a > b",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["true"],
        )
        self.expect(
            "expr --allow-jit false  -- a >= b",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["true"],
        )
        self.expect(
            "expr --allow-jit false  -- a < b",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["false"],
        )
        self.expect(
            "expr --allow-jit false  -- a <= b",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["false"],
        )
        self.expect(
            "expr --allow-jit false  -- a == b",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["false"],
        )
        self.expect(
            "expr --allow-jit false  -- a != b",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["true"],
        )

        # test single
        self.expect(
            "expr --allow-jit false  -- f + q",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["float", "44"],
        )
        self.expect(
            "expr --allow-jit false  -- f - q",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["float", "40"],
        )
        self.expect(
            "expr --allow-jit false  -- f / q",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["float", "21"],
        )
        self.expect(
            "expr --allow-jit false  -- f * q",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["float", "84"],
        )
        self.expect(
            "expr --allow-jit false  -- f + 2",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["float", "44"],
        )
        self.expect(
            "expr --allow-jit false  -- f > q",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["true"],
        )
        self.expect(
            "expr --allow-jit false  -- f >= q",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["true"],
        )
        self.expect(
            "expr --allow-jit false  -- f < q",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["false"],
        )
        self.expect(
            "expr --allow-jit false  -- f <= q",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["false"],
        )
        self.expect(
            "expr --allow-jit false  -- f == q",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["false"],
        )
        self.expect(
            "expr --allow-jit false  -- f != q",
            VARIABLES_DISPLAYED_CORRECTLY,
            substrs=["true"],
        )

        # compare jit and interpreter output
        self.assertTrue(self.process().IsValid())
        thread = lldbutil.get_stopped_thread(self.process(), lldb.eStopReasonBreakpoint)
        self.assertTrue(thread.IsValid())
        frame = thread.GetSelectedFrame()
        self.assertTrue(frame.IsValid())

        dividents = [42, 79, 666]
        divisors = [1.618, 2.718281828, 3.1415926535, 6.62607015]

        for x in dividents:
            for y in divisors:
                vardef = "double x = {0}, y = {1};".format(x, y)
                v1 = frame.EvaluateExpression(
                    "{0}; eval(x, y, 2)".format(vardef), self.jit_opts
                )
                v2 = frame.EvaluateExpression(
                    "{0}; x / y".format(vardef), self.no_jit_opts
                )
                self.assertTrue(v1.IsValid() and v2.IsValid())
                self.assertEqual(str(v1.GetData()), str(v2.GetData()))
