// Copyright 2018 The Dawn Authors
//
// 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 <gmock/gmock.h>
#include "tests/DawnTest.h"

#include <array>
#include <cstring>

using namespace testing;

class MockFenceOnCompletionCallback {
  public:
    MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};

static std::unique_ptr<MockFenceOnCompletionCallback> mockFenceOnCompletionCallback;
static void ToMockFenceOnCompletionCallback(WGPUFenceCompletionStatus status, void* userdata) {
    mockFenceOnCompletionCallback->Call(status, userdata);
}

class MockPopErrorScopeCallback {
  public:
    MOCK_METHOD(void, Call, (WGPUErrorType type, const char* message, void* userdata));
};

static std::unique_ptr<MockPopErrorScopeCallback> mockPopErrorScopeCallback;
static void ToMockPopErrorScopeCallback(WGPUErrorType type, const char* message, void* userdata) {
    mockPopErrorScopeCallback->Call(type, message, userdata);
}

class FenceTests : public DawnTest {
  private:
    struct CallbackInfo {
        FenceTests* test;
        uint64_t value;
        WGPUFenceCompletionStatus status;
        int32_t callIndex = -1;  // If this is -1, the callback was not called

        void Update(WGPUFenceCompletionStatus status) {
            this->callIndex = test->mCallIndex++;
            this->status = status;
        }
    };

    int32_t mCallIndex;

  protected:
    FenceTests() : mCallIndex(0) {
    }

    void TestSetUp() override {
        DawnTest::TestSetUp();
        mockFenceOnCompletionCallback = std::make_unique<MockFenceOnCompletionCallback>();
        mockPopErrorScopeCallback = std::make_unique<MockPopErrorScopeCallback>();
    }

    void TearDown() override {
        mockFenceOnCompletionCallback = nullptr;
        mockPopErrorScopeCallback = nullptr;
        DawnTest::TearDown();
    }

    void WaitForCompletedValue(wgpu::Fence fence, uint64_t completedValue) {
        while (fence.GetCompletedValue() < completedValue) {
            WaitABit();
        }
    }
};

// Test that signaling a fence updates the completed value
TEST_P(FenceTests, SimpleSignal) {
    wgpu::FenceDescriptor descriptor;
    descriptor.initialValue = 1u;
    wgpu::Fence fence = queue.CreateFence(&descriptor);

    // Completed value starts at initial value
    EXPECT_EQ(fence.GetCompletedValue(), 1u);

    queue.Signal(fence, 2);
    WaitForCompletedValue(fence, 2);

    // Completed value updates to signaled value
    EXPECT_EQ(fence.GetCompletedValue(), 2u);
}

// Test callbacks are called in increasing order of fence completion value
TEST_P(FenceTests, OnCompletionOrdering) {
    wgpu::Fence fence = queue.CreateFence();

    queue.Signal(fence, 4);

    {
        testing::InSequence s;

        EXPECT_CALL(*mockFenceOnCompletionCallback,
                    Call(WGPUFenceCompletionStatus_Success, this + 0))
            .Times(1);

        EXPECT_CALL(*mockFenceOnCompletionCallback,
                    Call(WGPUFenceCompletionStatus_Success, this + 1))
            .Times(1);

        EXPECT_CALL(*mockFenceOnCompletionCallback,
                    Call(WGPUFenceCompletionStatus_Success, this + 2))
            .Times(1);

        EXPECT_CALL(*mockFenceOnCompletionCallback,
                    Call(WGPUFenceCompletionStatus_Success, this + 3))
            .Times(1);
    }

    fence.OnCompletion(2u, ToMockFenceOnCompletionCallback, this + 2);
    fence.OnCompletion(0u, ToMockFenceOnCompletionCallback, this + 0);
    fence.OnCompletion(3u, ToMockFenceOnCompletionCallback, this + 3);
    fence.OnCompletion(1u, ToMockFenceOnCompletionCallback, this + 1);

    WaitForCompletedValue(fence, 4);
}

// Test callbacks still occur if Queue::Signal happens multiple times
TEST_P(FenceTests, MultipleSignalOnCompletion) {
    wgpu::Fence fence = queue.CreateFence();

    queue.Signal(fence, 2);
    queue.Signal(fence, 4);

    EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
        .Times(1);
    fence.OnCompletion(3u, ToMockFenceOnCompletionCallback, nullptr);

    WaitForCompletedValue(fence, 4);
}

// Test all callbacks are called if they are added for the same fence value
TEST_P(FenceTests, OnCompletionMultipleCallbacks) {
    wgpu::Fence fence = queue.CreateFence();

    queue.Signal(fence, 4);

    EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 0))
        .Times(1);

    EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 1))
        .Times(1);

    EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 2))
        .Times(1);

    EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 3))
        .Times(1);

    fence.OnCompletion(4u, ToMockFenceOnCompletionCallback, this + 0);
    fence.OnCompletion(4u, ToMockFenceOnCompletionCallback, this + 1);
    fence.OnCompletion(4u, ToMockFenceOnCompletionCallback, this + 2);
    fence.OnCompletion(4u, ToMockFenceOnCompletionCallback, this + 3);

    WaitForCompletedValue(fence, 4u);
}

// TODO(enga): Enable when fence is removed from fence signal tracker
// Currently it holds a reference and is not destructed
TEST_P(FenceTests, DISABLED_DestroyBeforeOnCompletionEnd) {
    wgpu::Fence fence = queue.CreateFence();

    // The fence in this block will be deleted when it goes out of scope
    {
        wgpu::Fence testFence = queue.CreateFence();

        queue.Signal(testFence, 4);

        EXPECT_CALL(*mockFenceOnCompletionCallback,
                    Call(WGPUFenceCompletionStatus_Unknown, this + 0))
            .Times(1);

        EXPECT_CALL(*mockFenceOnCompletionCallback,
                    Call(WGPUFenceCompletionStatus_Unknown, this + 1))
            .Times(1);

        EXPECT_CALL(*mockFenceOnCompletionCallback,
                    Call(WGPUFenceCompletionStatus_Unknown, this + 2))
            .Times(1);

        EXPECT_CALL(*mockFenceOnCompletionCallback,
                    Call(WGPUFenceCompletionStatus_Unknown, this + 3))
            .Times(1);

        testFence.OnCompletion(1u, ToMockFenceOnCompletionCallback, this + 0);
        testFence.OnCompletion(2u, ToMockFenceOnCompletionCallback, this + 1);
        testFence.OnCompletion(2u, ToMockFenceOnCompletionCallback, this + 2);
        testFence.OnCompletion(3u, ToMockFenceOnCompletionCallback, this + 3);
    }

    // Wait for another fence to be sure all callbacks have cleared
    queue.Signal(fence, 1);
    WaitForCompletedValue(fence, 1);
}

// Regression test that validation errors that are tracked client-side are captured
// in error scopes.
TEST_P(FenceTests, ClientValidationErrorInErrorScope) {
    wgpu::Fence fence = queue.CreateFence();

    queue.Signal(fence, 4);

    device.PushErrorScope(wgpu::ErrorFilter::Validation);
    queue.Signal(fence, 2);

    EXPECT_CALL(*mockPopErrorScopeCallback, Call(WGPUErrorType_Validation, _, this)).Times(1);
    device.PopErrorScope(ToMockPopErrorScopeCallback, this);

    WaitForCompletedValue(fence, 4);
}

DAWN_INSTANTIATE_TEST(FenceTests, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend());
