/*
 ** Copyright 2011, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 **
 **     http://www.apache.org/licenses/LICENSE-2.0
 **
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */

#include "header.h"
#include "gtest/gtest.h"
#include "egl_tls.h"
#include "hooks.h"

namespace android
{
extern FILE * file;
extern unsigned int MAX_FILE_SIZE;
extern pthread_key_t dbgEGLThreadLocalStorageKey;
};

// tmpfile fails, so need to manually make a writable file first
static const char * filePath = "/data/local/tmp/dump.gles2dbg";

class ServerFileTest : public ::testing::Test
{
protected:
    ServerFileTest() { }

    virtual ~ServerFileTest() { }

    virtual void SetUp() {
        MAX_FILE_SIZE = 8 << 20;
        ASSERT_EQ((FILE *)NULL, file);
        file = fopen("/data/local/tmp/dump.gles2dbg", "wb+");
        ASSERT_NE((FILE *)NULL, file) << "make sure file is writable: "
        << filePath;
    }

    virtual void TearDown() {
        ASSERT_NE((FILE *)NULL, file);
        fclose(file);
        file = NULL;
    }

    void Read(glesv2debugger::Message & msg) const {
        msg.Clear();
        uint32_t len = 0;
        ASSERT_EQ(sizeof(len), fread(&len, 1, sizeof(len), file));
        ASSERT_GT(len, 0u);
        char * buffer = new char [len];
        ASSERT_EQ(len, fread(buffer, 1, len, file));
        msg.ParseFromArray(buffer, len);
        delete buffer;
    }

    void CheckNoAvailable() {
        const long pos = ftell(file);
        fseek(file, 0, SEEK_END);
        EXPECT_EQ(pos, ftell(file)) << "check no available";
    }
};

TEST_F(ServerFileTest, Send)
{
    glesv2debugger::Message msg, cmd, read;
    msg.set_context_id(1);
    msg.set_function(msg.glFinish);
    msg.set_expect_response(false);
    msg.set_type(msg.BeforeCall);
    rewind(file);
    android::Send(msg, cmd);
    rewind(file);
    Read(read);
    EXPECT_EQ(msg.context_id(), read.context_id());
    EXPECT_EQ(msg.function(), read.function());
    EXPECT_EQ(msg.expect_response(), read.expect_response());
    EXPECT_EQ(msg.type(), read.type());
}

TEST_F(ServerFileTest, CreateDbgContext)
{
    gl_hooks_t hooks;
    struct Constant {
        GLenum pname;
        GLint param;
    };
    static const Constant constants [] = {
        {GL_MAX_VERTEX_ATTRIBS, 16},
        {GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 32},
        {GL_IMPLEMENTATION_COLOR_READ_FORMAT, GL_RGBA},
        {GL_IMPLEMENTATION_COLOR_READ_TYPE, GL_UNSIGNED_BYTE},
    };
    struct HookMock {
        static void GetIntegerv(GLenum pname, GLint* params) {
            ASSERT_TRUE(params != NULL);
            for (unsigned int i = 0; i < sizeof(constants) / sizeof(*constants); i++)
                if (pname == constants[i].pname) {
                    *params = constants[i].param;
                    return;
                }
            FAIL() << "GetIntegerv unknown pname: " << pname;
        }
        static GLenum GetError() {
            return GL_NO_ERROR;
        }
    };
    hooks.gl.glGetError = HookMock::GetError;
    hooks.gl.glGetIntegerv = HookMock::GetIntegerv;
    DbgContext * const dbg = CreateDbgContext(-1, 1, &hooks);
    ASSERT_TRUE(dbg != NULL);
    EXPECT_TRUE(dbg->vertexAttribs != NULL);

    rewind(file);
    glesv2debugger::Message read;
    for (unsigned int i = 0; i < 2; i++) {
        Read(read);
        EXPECT_EQ(reinterpret_cast<int>(dbg), read.context_id());
        EXPECT_FALSE(read.expect_response());
        EXPECT_EQ(read.Response, read.type());
        EXPECT_EQ(read.SETPROP, read.function());
        EXPECT_EQ(read.GLConstant, read.prop());
        GLint expectedConstant = 0;
        HookMock::GetIntegerv(read.arg0(), &expectedConstant);
        EXPECT_EQ(expectedConstant, read.arg1());
    }
    CheckNoAvailable();
    DestroyDbgContext(dbg);
}

void * glNoop()
{
    return 0;
}

class ServerFileContextTest : public ServerFileTest
{
protected:
    tls_t tls;
    gl_hooks_t hooks;

    ServerFileContextTest() { }

    virtual ~ServerFileContextTest() { }

    virtual void SetUp() {
        ServerFileTest::SetUp();

        if (dbgEGLThreadLocalStorageKey == -1)
            pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL);
        ASSERT_NE(-1, dbgEGLThreadLocalStorageKey);
        tls.dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE);
        ASSERT_NE((void *)NULL, tls.dbg);
        pthread_setspecific(dbgEGLThreadLocalStorageKey, &tls);
        for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
            ((void **)&hooks)[i] = reinterpret_cast<void *>(glNoop);
    }

    virtual void TearDown() {
        ServerFileTest::TearDown();
    }
};

TEST_F(ServerFileContextTest, MessageLoop)
{
    static const int arg0 = 45;
    static const float arg7 = -87.2331f;
    static const int arg8 = -3;
    static const int * ret = reinterpret_cast<int *>(870);

    struct Caller : public FunctionCall {
        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
            msg.set_arg0(arg0);
            msg.set_arg7((int &)arg7);
            msg.set_arg8(arg8);
            return ret;
        }
    } caller;
    const int contextId = reinterpret_cast<int>(tls.dbg);
    glesv2debugger::Message msg, read;

    EXPECT_EQ(ret, MessageLoop(caller, msg, msg.glFinish));

    rewind(file);
    Read(read);
    EXPECT_EQ(contextId, read.context_id());
    EXPECT_EQ(read.glFinish, read.function());
    EXPECT_EQ(false, read.expect_response());
    EXPECT_EQ(read.BeforeCall, read.type());

    Read(read);
    EXPECT_EQ(contextId, read.context_id());
    EXPECT_EQ(read.glFinish, read.function());
    EXPECT_EQ(false, read.expect_response());
    EXPECT_EQ(read.AfterCall, read.type());
    EXPECT_TRUE(read.has_time());
    EXPECT_EQ(arg0, read.arg0());
    const int readArg7 = read.arg7();
    EXPECT_EQ(arg7, (float &)readArg7);
    EXPECT_EQ(arg8, read.arg8());

    const long pos = ftell(file);
    fseek(file, 0, SEEK_END);
    EXPECT_EQ(pos, ftell(file))
    << "should only write the BeforeCall and AfterCall messages";
}

TEST_F(ServerFileContextTest, DisableEnableVertexAttribArray)
{
    Debug_glEnableVertexAttribArray(tls.dbg->MAX_VERTEX_ATTRIBS + 2); // should just ignore invalid index

    glesv2debugger::Message read;
    rewind(file);
    Read(read);
    EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
    EXPECT_EQ(tls.dbg->MAX_VERTEX_ATTRIBS + 2, read.arg0());
    Read(read);

    rewind(file);
    Debug_glDisableVertexAttribArray(tls.dbg->MAX_VERTEX_ATTRIBS + 4); // should just ignore invalid index
    rewind(file);
    Read(read);
    Read(read);

    for (unsigned int i = 0; i < tls.dbg->MAX_VERTEX_ATTRIBS; i += 5) {
        rewind(file);
        Debug_glEnableVertexAttribArray(i);
        EXPECT_TRUE(tls.dbg->vertexAttribs[i].enabled);
        rewind(file);
        Read(read);
        EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
        EXPECT_EQ(i, read.arg0());
        Read(read);

        rewind(file);
        Debug_glDisableVertexAttribArray(i);
        EXPECT_FALSE(tls.dbg->vertexAttribs[i].enabled);
        rewind(file);
        Read(read);
        EXPECT_EQ(read.glDisableVertexAttribArray, read.function());
        EXPECT_EQ(i, read.arg0());
        Read(read);
    }
}
