// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Extension unit tests for the mpv backend wrapper (suite: mpv_proxy_ext).
//
// Goal: raise line coverage of src/backends/mpv/mpv_proxy.cpp by exercising the
// STANDALONE, backend-free pieces of the file: the MpvHandle refcounted
// container (null-handle path, where the mpv C API is never called), the
// my_node_autofree RAII helper, and the Q_OBJECT-generated tr().
//
// CRASH SAFETY: the rest of MpvProxy drives a live libmpv handle (mpv_create /
// mpv_initialize / decode). Constructing MpvProxy and destroying it touches a
// live backend and window handles -> SIGSEGV risk that would drop coverage for
// every later case. We therefore ONLY exercise the pure, backend-free helpers
// and deliberately do NOT instantiate MpvProxy here.

#include <QtTest>
#include <QTest>
#include <QDebug>
#include <QVariant>
#include <mpv/client.h>

#include <gtest/gtest.h>

#define protected public
#define private public
#include "src/backends/mpv/mpv_proxy.h"
#undef protected
#undef private

#include "utils.h"

using namespace dmr;

// ---------- helpers (unique prefix mpx_) ----------

// ==========================================================================
// MpvHandle::container — refcounted holder for an mpv_handle. Its destructor
// only calls into libmpv when the handle is non-null, so wrapping a nullptr
// exercises the ctor + the null-guarded dtor path safely (no mpv symbols used).
// ==========================================================================

TEST(mpv_proxy_ext, MpvHandle_FromRawHandle_Null_DestructsSafely)
{
    // Scope so the container's dtor runs (covers the null-handle branch).
    {
        MpvHandle h = MpvHandle::fromRawHandle(nullptr);
        // operator mpv_handle* returns the raw pointer (nullptr here).
        mpv_handle *raw = h;
        EXPECT_EQ(raw, nullptr);
    }
    SUCCEED();
}

TEST(mpv_proxy_ext, MpvHandle_DefaultConstructed_OperatorReturnsZero)
{
    MpvHandle h;   // empty QSharedPointer -> operator mpv_handle* returns 0
    mpv_handle *raw = h;
    EXPECT_EQ(raw, (mpv_handle *)0);
}

TEST(mpv_proxy_ext, MpvHandle_Copy_SharesContainer)
{
    MpvHandle a = MpvHandle::fromRawHandle(nullptr);
    MpvHandle b = a;   // shared-pointer copy, same container
    mpv_handle *ra = a;
    mpv_handle *rb = b;
    EXPECT_EQ(ra, rb);
}

// ==========================================================================
// MpvProxy::my_node_autofree — RAII wrapper that calls mpv_freeNode_contents on
// destruction. With a node of format MPV_FORMAT_NONE the free is a no-op, so
// this is safe and exercises both ctor and dtor.
// ==========================================================================

TEST(mpv_proxy_ext, MyNodeAutofree_NoneFormat_ConstructAndDestroy)
{
    mpv_node node;
    node.format = MPV_FORMAT_NONE;
    {
        MpvProxy::my_node_autofree af(&node);
        EXPECT_EQ(af.pNode, &node);
    }   // dtor runs mpv_freeNode_contents -> no-op for NONE
    SUCCEED();
}

TEST(mpv_proxy_ext, MyNodeAutofree_FlagNode_ConstructAndDestroy)
{
    mpv_node node;
    node.format = MPV_FORMAT_FLAG;
    node.u.flag = 1;
    {
        MpvProxy::my_node_autofree af(&node);
        EXPECT_EQ(af.pNode->u.flag, 1);
    }   // dtor no-op for flag
    SUCCEED();
}

// ==========================================================================
// MpvProxy::tr — Q_OBJECT-generated static translator. Pure, backend-free.
// ==========================================================================

TEST(mpv_proxy_ext, MpvProxy_Tr_ReturnsNonEmpty)
{
    // tr() is generated by Q_OBJECT; resolves against the class context.
    QString s = MpvProxy::tr("Play");
    EXPECT_FALSE(s.isEmpty());
}
