"""
We don't have real tests for the cache, but it would be great to make them!

But this one tests a current behavior that isn't good: the c_code isn't
deterministic based on the input type and the op.
"""
from __future__ import absolute_import, print_function, division

import numpy as np

import theano
from theano.gof.cmodule import GCC_compiler


class MyOp(theano.compile.ops.DeepCopyOp):
    nb_called = 0

    def c_code_cache_version(self):
        return ()

    def c_code(self, node, name, inames, onames, sub):
        MyOp.nb_called += 1
        iname, = inames
        oname, = onames
        fail = sub['fail']
        itype = node.inputs[0].type.__class__
        if itype in self.c_code_and_version:
            code, version = self.c_code_and_version[itype]
            rand = np.random.rand()
            return ("printf(\"%(rand)s\\n\");" + code) % locals()
        # Else, no C code
        return super(theano.compile.ops.DeepCopyOp, self).c_code(
            node, name, inames, onames, sub)


def test_inter_process_cache():
    # When an op with c_code, but no version. If we have 2 apply node
    # in the graph with different inputs variable(so they don't get
    # merged) but the inputs variable have the same type, do we reuse
    # the same module? Even if they would generate different c_code?
    # Currently this test show that we generate the c_code only once.
    #
    # This is to know if the c_code can add information specific to the
    # node.inputs[*].owner like the name of the variable.

    x, y = theano.tensor.dvectors('xy')
    f = theano.function([x, y], [MyOp()(x), MyOp()(y)])
    f(np.arange(60), np.arange(60))
    if theano.config.mode == 'FAST_COMPILE' or theano.config.cxx == "":
        assert MyOp.nb_called == 0
    else:
        assert MyOp.nb_called == 1

    # What if we compile a new function with new variables?
    x, y = theano.tensor.dvectors('xy')
    f = theano.function([x, y], [MyOp()(x), MyOp()(y)])
    f(np.arange(60), np.arange(60))
    if theano.config.mode == 'FAST_COMPILE' or theano.config.cxx == "":
        assert MyOp.nb_called == 0
    else:
        assert MyOp.nb_called == 1


def test_flag_detection():
    # Check that the code detecting blas flags does not raise any exception.
    # It used to happen on python 3 because of improper string handling,
    # but was not detected because that path is not usually taken,
    # so we test it here directly.
    GCC_compiler.try_flags(["-lblas"])
