mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-15 05:53:23 +09:00
- Layout only: token streams match up to split literals, continuations and using order - The size totals fall, so the structure baseline is lowered
66 lines
3.6 KiB
C++
66 lines
3.6 KiB
C++
// MobileGL - MobileGL/MG_Test/ScopedPipeVerb.h
|
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
// Licensed under the GNU Lesser General Public License v3.0:
|
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
// End of Source File Header
|
|
|
|
#pragma once
|
|
#include <MG_Pipe/MGPipe.h>
|
|
#include <MG_Impl/Pipe/PipeFill.h>
|
|
|
|
namespace MobileGL::MG_Test {
|
|
// "This test is standing inside verb X."
|
|
//
|
|
// A unit test that constructs a GLContext by hand and then calls a BACKEND helper
|
|
// directly enters through no GL entry point, so no MGP_FILL ever fires (P1 brief D7) and
|
|
// in a push build the PipeInputs block the helper's gPipeInputs reads is empty and unstamped:
|
|
// its first accessor read is Fatal{UnmigratedPipeInput, "Field@<none>"}. The test is
|
|
// right and the poison is right - what was missing is the verb, and this object is how a
|
|
// test states it. Constructing it runs the real filler for `verb`, exactly the call
|
|
// MG_Impl makes before that verb reaches a backend; destroying it leaves the verb again.
|
|
//
|
|
// It is not an escape hatch and it weakens nothing:
|
|
// - it fills exactly kMGPipeClassFieldMask[class of verb] out of the live GLContext, so
|
|
// a read of a field that verb does not fill is still Fatal, naming the field and this
|
|
// verb - the fill table stays the only thing that says what a verb may read;
|
|
// - leaving the scope re-arms the poison. The exit fill is a kQuery verb, whose class
|
|
// mask is a single field, so every field this scope stamped goes stale the moment the
|
|
// scope ends. That matters when the suite runs as one process (a developer running
|
|
// the test binary directly, rather than one ctest entry per case): without it, one
|
|
// case's declaration would cover a later case that forgot to make one;
|
|
// - it is a no-op in the pull build, where gPipeInputs is the live context and there is
|
|
// nothing to fill, so the pull build stays byte-identical.
|
|
//
|
|
// Place it the way MGP_FILL is placed in production (P1 brief D7): immediately BEFORE the
|
|
// backend call, after every frontend mutation that call is meant to see. A test that
|
|
// drives the helper again with frontend state changed in between issues a second verb -
|
|
// Renew() - because that is what a second GL entry point would have done. A test that
|
|
// drives a helper of a DIFFERENT verb class opens a nested scope for it.
|
|
class ScopedPipeVerb {
|
|
public:
|
|
explicit ScopedPipeVerb([[maybe_unused]] MG_Pipe::MGPipeVerb verb) : m_verb(verb) {
|
|
MG_Pipe::MGPipeValidateForVerb(m_verb);
|
|
}
|
|
|
|
ScopedPipeVerb(const ScopedPipeVerb&) = delete;
|
|
ScopedPipeVerb& operator=(const ScopedPipeVerb&) = delete;
|
|
|
|
// A second verb of the same kind begins: re-fill and re-stamp, so a helper driven
|
|
// again after the test moved frontend state sees the new values, the way the next GL
|
|
// entry point's MGP_FILL would.
|
|
void Renew() { MG_Pipe::MGPipeValidateForVerb(m_verb); }
|
|
|
|
// Leaving bumps the serial and puts the current verb back to "none": every field
|
|
// this scope stamped goes stale, and a later test that forgets its own declaration
|
|
// aborts with "<Field>@<none>" rather than with the name of a verb it never issued.
|
|
// That matters when the suite runs as one process (a developer running the test
|
|
// binary directly, rather than one ctest entry per case).
|
|
~ScopedPipeVerb() { MG_Pipe::MGPipeLeaveVerb(); }
|
|
|
|
private:
|
|
MG_Pipe::MGPipeVerb m_verb;
|
|
};
|
|
} // namespace MobileGL::MG_Test
|