jsuno: Throw css.script.provider.ScriptExceptionRaisedException on JS errors

Signed-off-by: Stephan Bergmann <stephan.bergmann@collabora.com>
Change-Id: Ia5df077d78b1650e28bf73716a10fdbd024f6e8a
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2077
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Michael Stahl <michael.stahl@collabora.com>
(cherry picked from commit a4feac2f06bf3d1a6ed55a94dd5e05d01fc0f7c4)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205118
Reviewed-by: Neil Roberts <nroberts@libreoffice.org>
Tested-by: Jenkins
This commit is contained in:
Stephan Bergmann
2026-05-13 09:05:48 +02:00
committed by Neil Roberts
parent bedeae9485
commit 368792e83c
5 changed files with 168 additions and 14 deletions
+1
View File
@@ -16,6 +16,7 @@
namespace jsuno
{
// @throws css.script.provider.ScriptExceptionRaisedException
LO_DLLPUBLIC_JSUNO void execute(OUString const& script);
}
+27
View File
@@ -0,0 +1,27 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Contributor(s):
# Copyright the Collabora Office contributors.
$(eval $(call gb_CppunitTest_CppunitTest,jsuno_execute))
$(eval $(call gb_CppunitTest_add_exception_objects,jsuno_execute, \
jsuno/qa/unit/execute \
))
$(eval $(call gb_CppunitTest_use_libraries,jsuno_execute, \
jsuno \
sal \
))
$(eval $(call gb_CppunitTest_use_sdk_api,jsuno_execute))
$(eval $(call gb_CppunitTest_use_ure,jsuno_execute))
# vim: set noet sw=4 ts=4:
+1
View File
@@ -15,6 +15,7 @@ $(eval $(call gb_Module_add_targets,jsuno, \
$(eval $(call gb_Module_add_check_targets,jsuno, \
$(if $(ENABLE_EMBINDTEST_UNO),CppunitTest_jsuno_testuno) \
CppunitTest_jsuno_execute \
))
# vim: set noet sw=4 ts=4:
+84
View File
@@ -0,0 +1,84 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Contributor(s):
* Copyright the Collabora Office contributors.
*/
#include <sal/config.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/plugin/TestPlugIn.h>
#include <com/sun/star/script/provider/ScriptExceptionRaisedException.hpp>
#include <jsuno/jsuno.hxx>
#include <rtl/ustring.hxx>
namespace
{
class Execute : public CppUnit::TestFixture
{
public:
void testThrows()
{
try
{
jsuno::execute(u"throw new Error('boom')"_ustr);
CPPUNIT_FAIL("expected ScriptExceptionRaisedException");
}
catch (css::script::provider::ScriptExceptionRaisedException const& e)
{
CPPUNIT_ASSERT(e.Message.startsWith("boom"));
CPPUNIT_ASSERT_EQUAL(u"<input>"_ustr, e.scriptName);
CPPUNIT_ASSERT_EQUAL(u"JavaScript"_ustr, e.language);
CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), e.lineNum);
CPPUNIT_ASSERT_EQUAL(u"Error"_ustr, e.exceptionType);
}
try
{
jsuno::execute(u"throw new TypeError('bad type')"_ustr);
CPPUNIT_FAIL("expected ScriptExceptionRaisedException");
}
catch (css::script::provider::ScriptExceptionRaisedException const& e)
{
CPPUNIT_ASSERT(e.Message.startsWith("bad type"));
CPPUNIT_ASSERT_EQUAL(u"TypeError"_ustr, e.exceptionType);
}
try
{
jsuno::execute(u"@@@ not valid JS"_ustr);
CPPUNIT_FAIL("expected ScriptExceptionRaisedException");
}
catch (css::script::provider::ScriptExceptionRaisedException const& e)
{
CPPUNIT_ASSERT_EQUAL(u"SyntaxError"_ustr, e.exceptionType);
}
try
{
jsuno::execute(u"throw 'plain string'"_ustr);
CPPUNIT_FAIL("expected ScriptExceptionRaisedException");
}
catch (css::script::provider::ScriptExceptionRaisedException const& e)
{
CPPUNIT_ASSERT(e.Message.startsWith("plain string"));
CPPUNIT_ASSERT_EQUAL(u""_ustr, e.exceptionType);
}
}
CPPUNIT_TEST_SUITE(Execute);
CPPUNIT_TEST(testThrows);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(Execute);
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
+55 -14
View File
@@ -39,6 +39,7 @@
#include <com/sun/star/script/Invocation.hpp>
#include <com/sun/star/script/InvocationInfo.hpp>
#include <com/sun/star/script/XInvocation2.hpp>
#include <com/sun/star/script/provider/ScriptExceptionRaisedException.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/uno/RuntimeException.hpp>
@@ -2435,6 +2436,56 @@ JSValue invokeUno(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst*
return ret.release();
});
}
struct ExceptionData
{
OUString type;
OUString message;
};
ExceptionData extractExceptionData(JSContext* ctx, ValueRef const& err)
{
ExceptionData exc;
bool haveMessage = false;
if (JS_IsObject(err))
{
ValueRef const nameVal(ctx, JS_GetPropertyStr(ctx, err, "name"));
if (JS_IsString(nameVal))
{
std::size_t n;
UniqueCString16 const p(ctx, JS_ToCStringLenUTF16(ctx, &n, nameVal));
if (p.get() != nullptr)
{
exc.type = OUString(p.get(), n);
}
}
ValueRef const msgVal(ctx, JS_GetPropertyStr(ctx, err, "message"));
if (JS_IsString(msgVal))
{
std::size_t n;
UniqueCString16 const p(ctx, JS_ToCStringLenUTF16(ctx, &n, msgVal));
if (p.get() != nullptr)
{
exc.message = OUString(p.get(), n);
haveMessage = true;
}
}
}
if (!haveMessage)
{
ValueRef const str(ctx, JS_ToString(ctx, err));
if (!JS_IsException(str))
{
std::size_t n;
UniqueCString16 const p(ctx, JS_ToCStringLenUTF16(ctx, &n, str));
if (p.get() != nullptr)
{
exc.message = OUString(p.get(), n);
}
}
}
return exc;
}
}
void jsuno::execute(OUString const& script)
@@ -2497,7 +2548,7 @@ void jsuno::execute(OUString const& script)
e = JS_NewClass(rt, getRuntimeData(rt)->moduleClassId, &moduleClass);
assert(e == 0); //TODO
auto const ctx = JS_NewContext(rt);
std::optional<OUString> exc;
std::optional<ExceptionData> exc;
{
ValueRef const global(ctx, JS_GetGlobalObject(ctx));
getRuntimeData(ctx)->symbolIteratorAtom = JS_ValueToAtom(
@@ -2560,18 +2611,7 @@ void jsuno::execute(OUString const& script)
//TODO: reconstruct UNO exceptions
ValueRef const err(ctx, JS_GetException(ctx));
assert(!JS_IsException(err)); //TODO?
ValueRef const str(ctx, JS_ToString(ctx, err));
assert(!JS_IsException(str)); //TODO?
std::size_t n1;
UniqueCString16 const p1(ctx, JS_ToCStringLenUTF16(ctx, &n1, str));
assert(p1.get() != nullptr); //TODO?
ValueRef const stack(ctx, JS_GetPropertyStr(ctx, err, "stack"));
assert(!JS_IsException(stack)); //TODO?
std::size_t n2;
UniqueCString16 const p2(ctx, JS_ToCStringLenUTF16(ctx, &n2, stack));
assert(p2.get() != nullptr); //TODO?
exc = OUString::Concat(std::u16string_view(p1.get(), n1)) + ": "
+ std::u16string_view(p2.get(), n2);
exc = extractExceptionData(ctx, err);
}
}
JS_FreeContext(ctx);
@@ -2580,7 +2620,8 @@ void jsuno::execute(OUString const& script)
JS_FreeRuntime(rt);
if (exc)
{
throw css::uno::RuntimeException("JS exception: " + *exc);
throw css::script::provider::ScriptExceptionRaisedException(
exc->message, {}, u"<input>"_ustr, u"JavaScript"_ustr, -1, exc->type);
}
}