ci: build the real OBS adapter on all three platforms
Two things: unbreak the Windows compile, and give macOS/Windows a libobs.
MSVC fix. test_json.cpp failed to compile on the Windows runner with
"a universal-character-name specifies an invalid character" and "illegal
escape sequence" -- MSVC still forms escape sequences and
universal-character-names INSIDE raw string literals, which it must not.
Every JSON input containing a backslash is now built by string concatenation
from a single kBS constant, which also sidesteps the separate murky corner of
translation phase 1 where a doubled backslash immediately followed by 'u' has
historically been treated inconsistently. Same 158 checks, no behaviour
change.
OBS SDK bootstrap for macOS/Windows. Adopts obsproject/obs-plugintemplate's
buildspec machinery -- buildspec.json plus cmake/common/buildspec_common.cmake
and cmake/{macos,windows}/buildspec.cmake -- so those two platforms get a real
libobs and build the actual plugin module instead of only the core library.
Linux is untouched and still uses Ubuntu's libobs-dev
(-DSTPLUGIN_BOOTSTRAP_OBS=OFF); the bootstrap only runs where there is no
system package.
Trimmed against upstream, each change recorded in the file that makes it:
- qt6 is dropped from dependencies_list on both platforms. The properties UI
is plain obs_properties_* and nothing here links Qt.
- The OBS sub-build builds and installs the `libobs` target, not
`obs-frontend-api`. Building the frontend API is what would drag Qt back in,
and this plugin never calls it.
- The sub-build is configured with ENABLE_UI=OFF and ENABLE_SCRIPTING=OFF as
well as upstream's ENABLE_FRONTEND=OFF: the pinned OBS predates
ENABLE_FRONTEND and gates its Qt-dependent UI on ENABLE_UI, so without this
it configures the whole OBS UI and demands Qt anyway.
- Only the Release configuration is built and installed, not Debug as well.
Nothing consumes a debug libobs and it doubles the slowest CI step.
- Only the dependency-acquisition modules are vendored. The template's
compilerconfig/defaults/helpers/xcode modules drive its own target and
bundle layout, which this project does not use.
obs-studio is pinned to 30.0.2, deliberately low: OBS refuses to load a module
built against a NEWER libobs than the one running it and accepts older ones, so
this pin IS the minimum OBS version users need. 30.0.2 is also exactly what
Ubuntu 24.04's libobs-dev ships, which puts all three platforms on one floor,
and it supports the modern CMake layout the bootstrap drives via
-DOBS_CMAKE_VERSION=3.0.0. prebuilt is obs-deps 2023-11-03 with the hashes
obs-studio 30.0.2's own buildspec.json publishes; the obs-studio source
archive hashes were computed from the GitHub tag archives.
The workflow also prints what was actually produced on each platform (ldd /
otool / dir over build/package) and uploads it as an artifact, so "does this
even link against libobs" is answered by CI output rather than assumed.
Verified locally: the Linux path is unchanged by all of this -- a fresh
configure still finds libobs-dev, and ctest is 6/6. The macOS and Windows
bootstrap can only be verified by CI; that is what this push is for.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
This commit is contained in:
+43
-18
@@ -17,6 +17,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "stplugin/json.h"
|
||||
#include "test_util.h"
|
||||
@@ -50,6 +51,24 @@ static void testRealResponses()
|
||||
ST_ASSERT_EQ(error["error"].asString(), std::string("not found"));
|
||||
}
|
||||
|
||||
// One backslash, as it appears in the JSON *text* being parsed.
|
||||
//
|
||||
// Every JSON input below that contains a backslash is built by concatenation
|
||||
// rather than written as a literal. Two separate portability problems make
|
||||
// the obvious spellings unsafe, both observed on the Windows CI runner:
|
||||
// - MSVC still forms escape sequences and universal-character-names inside
|
||||
// RAW string literals, which it must not: R"( ... backslash-u-d-8-3-d ... )"
|
||||
// is a hard compile error ("a universal-character-name specifies an
|
||||
// invalid character"), and a raw string containing backslash-slash is an
|
||||
// "illegal escape sequence".
|
||||
// - A doubled backslash immediately followed by 'u' inside an ordinary
|
||||
// literal sits on a genuinely murky corner of translation phase 1, where
|
||||
// compilers have historically disagreed about whether a
|
||||
// universal-character-name is formed.
|
||||
// Concatenation sidesteps both: no backslash is ever adjacent to a 'u' in
|
||||
// the source text at all.
|
||||
static const std::string kBS = "\\";
|
||||
|
||||
static void testScalarsAndEscapes()
|
||||
{
|
||||
ST_ASSERT(parse("null").isNull());
|
||||
@@ -59,14 +78,20 @@ static void testScalarsAndEscapes()
|
||||
ST_ASSERT_EQ(parse("-12").asNumber(), -12.0);
|
||||
ST_ASSERT_EQ(parse("1.5e2").asNumber(), 150.0);
|
||||
ST_ASSERT_EQ(parse("\"\"").asString("x"), std::string(""));
|
||||
ST_ASSERT_EQ(parse(R"("a\"b\\c\/d")").asString(), std::string("a\"b\\c/d"));
|
||||
ST_ASSERT_EQ(parse(R"("\n\t\r\b\f")").asString(), std::string("\n\t\r\b\f"));
|
||||
|
||||
// \u escapes, including a surrogate pair (an emoji in a display name is
|
||||
// entirely plausible and must not corrupt the dropdown).
|
||||
ST_ASSERT_EQ(parse(R"("\u0041")").asString(), std::string("A"));
|
||||
ST_ASSERT_EQ(parse(R"("caf\u00e9")").asString(), std::string("caf\xc3\xa9"));
|
||||
ST_ASSERT_EQ(parse(R"("\ud83d\ude00")").asString(), std::string("\xf0\x9f\x98\x80"));
|
||||
// "a\"b\\c\/d" -> a"b\c/d
|
||||
ST_ASSERT_EQ(parse("\"a" + kBS + "\"b" + kBS + kBS + "c" + kBS + "/d\"").asString(),
|
||||
std::string("a\"b\\c/d"));
|
||||
// "\n\t\r\b\f"
|
||||
ST_ASSERT_EQ(parse("\"" + kBS + "n" + kBS + "t" + kBS + "r" + kBS + "b" + kBS + "f\"").asString(),
|
||||
std::string("\n\t\r\b\f"));
|
||||
|
||||
// \uXXXX escapes, including a surrogate pair (an emoji in a display name
|
||||
// is entirely plausible and must not corrupt the dropdown).
|
||||
ST_ASSERT_EQ(parse("\"" + kBS + "u0041\"").asString(), std::string("A"));
|
||||
ST_ASSERT_EQ(parse("\"caf" + kBS + "u00e9\"").asString(), std::string("caf\xc3\xa9"));
|
||||
ST_ASSERT_EQ(parse("\"" + kBS + "ud83d" + kBS + "ude00\"").asString(),
|
||||
std::string("\xf0\x9f\x98\x80"));
|
||||
|
||||
// Whitespace everywhere legal.
|
||||
ST_ASSERT_EQ(parse(" {\n \"a\" :\t[ 1 , 2 ]\r\n} ")["a"].size(), std::size_t(2));
|
||||
@@ -74,7 +99,7 @@ static void testScalarsAndEscapes()
|
||||
|
||||
static void testMalformedIsRejectedNotCrashed()
|
||||
{
|
||||
const char *bad[] = {
|
||||
const std::vector<std::string> bad = {
|
||||
"",
|
||||
" ",
|
||||
"{",
|
||||
@@ -88,12 +113,12 @@ static void testMalformedIsRejectedNotCrashed()
|
||||
"{a:1}",
|
||||
"{'a':1}",
|
||||
"\"unterminated",
|
||||
"\"bad\\escape\"",
|
||||
"\"\\u00\"",
|
||||
"\"\\uZZZZ\"",
|
||||
"\"\\ud83d\"", // lone high surrogate
|
||||
"\"\\ude00\"", // lone low surrogate
|
||||
"01", // leading zero
|
||||
"\"bad" + kBS + "escape\"", // not a JSON escape character
|
||||
"\"" + kBS + "u00\"", // truncated code point
|
||||
"\"" + kBS + "uZZZZ\"", // non-hex code point
|
||||
"\"" + kBS + "ud83d\"", // lone high surrogate
|
||||
"\"" + kBS + "ude00\"", // lone low surrogate
|
||||
"01", // leading zero
|
||||
"+1",
|
||||
".5",
|
||||
"1.",
|
||||
@@ -101,13 +126,13 @@ static void testMalformedIsRejectedNotCrashed()
|
||||
"1e+",
|
||||
"tru",
|
||||
"nulll",
|
||||
"{}garbage", // trailing content
|
||||
"{}garbage", // trailing content
|
||||
"[1,2] [3]",
|
||||
"\"raw\ncontrol\"", // literal control char inside a string
|
||||
"\xff\xfe", // binary garbage, e.g. an HTML error page prefix
|
||||
"\"raw\ncontrol\"", // literal control char inside a string
|
||||
"\xff\xfe", // binary garbage
|
||||
"<!DOCTYPE html><html><body>502 Bad Gateway</body></html>",
|
||||
};
|
||||
for (const char *text : bad) {
|
||||
for (const std::string &text : bad) {
|
||||
const Value v = parse(text);
|
||||
ST_ASSERT(!v.valid());
|
||||
// Accessors on an invalid value must still be safe and return the
|
||||
|
||||
Reference in New Issue
Block a user