From 52172c7d23d803f4fb43b682c4fc1675a5bbc61a Mon Sep 17 00:00:00 2001 From: Sidhanth B H Date: Thu, 27 Nov 2025 17:39:20 +0530 Subject: [PATCH] RDKEMW-9785: Increasing Test Coverage for L1 test Reason for change: Overall test coverage should 75% Test Procedure: Build should be successful Risk:low Priority:P2 --- include/JSRuntimeClient.h | 11 ++ include/JSRuntimeServer.h | 15 +++ include/jsc/JavaScriptContext.h | 9 ++ include/jsc/JavaScriptWrapper.h | 4 + include/jsc/PlayerEventHandler.h | 5 + include/jsc/PlayerWrapper.h | 51 +++++++ include/rtWebSocket.h | 1 + src/jsc/JavaScriptWrapper.cpp | 9 ++ src/jsc/PlayerWrapper.cpp | 26 +++- src/jsc/jsc_lib/jsc_lib.cpp | 220 ++++++++++++++++++++++++++++++- src/jsc/jsc_lib/jsc_lib.h | 23 +++- 11 files changed, 365 insertions(+), 9 deletions(-) diff --git a/include/JSRuntimeClient.h b/include/JSRuntimeClient.h index 586223a..a34588a 100644 --- a/include/JSRuntimeClient.h +++ b/include/JSRuntimeClient.h @@ -90,12 +90,23 @@ class JSRuntimeClient : public CommandInterface std::string getState(); +#ifdef UNIT_TEST_BUILD +protected: + void onMessage(websocketpp::connection_hdl hdl, message_ptr msg); + void setState(const std::string &state); + void onOpen(websocketpp::connection_hdl hdl); + void onFail(websocketpp::connection_hdl hdl); + void onClose(websocketpp::connection_hdl hdl); +#endif + +#ifndef UNIT_TEST_BUILD private: void onMessage(websocketpp::connection_hdl hdl, message_ptr msg); void setState(const std::string &state); void onOpen(websocketpp::connection_hdl hdl); void onFail(websocketpp::connection_hdl hdl); void onClose(websocketpp::connection_hdl hdl); +#endif private: JSRuntimeClient(); diff --git a/include/JSRuntimeServer.h b/include/JSRuntimeServer.h index e6850cc..d9f0616 100644 --- a/include/JSRuntimeServer.h +++ b/include/JSRuntimeServer.h @@ -45,10 +45,25 @@ class JSRuntimeServer bool stop(); private: +#ifdef UNIT_TEST_BUILD +public: + // Expose private methods for testing void send(websocketpp::connection_hdl hdl, const std::string &msg); void onMessage(websocketpp::connection_hdl hdl, message_ptr msg); void onOpen(websocketpp::connection_hdl hdl); void onClose(websocketpp::connection_hdl hdl); + + const std::set>& getConnections() const { return mConnections; } + WsServer& getServer() { return mServer; } +#endif + +#ifndef UNIT_TEST_BUILD +private: + void send(websocketpp::connection_hdl hdl, const std::string &msg); + void onMessage(websocketpp::connection_hdl hdl, message_ptr msg); + void onOpen(websocketpp::connection_hdl hdl); + void onClose(websocketpp::connection_hdl hdl); +#endif private: typedef std::set> ConnectionSet; diff --git a/include/jsc/JavaScriptContext.h b/include/jsc/JavaScriptContext.h index a97c6d3..caf0164 100644 --- a/include/jsc/JavaScriptContext.h +++ b/include/jsc/JavaScriptContext.h @@ -91,8 +91,16 @@ class JavaScriptContext: public JavaScriptContextBase, public NetworkMetricsList double getExecutionDuration() const; void handleExternalApplication(const std::string& url); +#ifdef UNIT_TEST_BUILD + bool evaluateScript(const char *script, const char *name, const char *args = nullptr, bool module = false); + void processKeyEvent(struct JavaScriptKeyDetails& details, bool keyPress); + void registerUtils(); + void loadAAMPJSBindingsLib(); + void unloadAAMPJSBindingsLib(); +#endif private: +#ifndef UNIT_TEST_BUILD bool evaluateScript(const char *script, const char *name, const char *args = nullptr, bool module = false); void processKeyEvent(struct JavaScriptKeyDetails& details, bool keyPress); void registerUtils(); @@ -102,6 +110,7 @@ class JavaScriptContext: public JavaScriptContextBase, public NetworkMetricsList void unloadAAMPJSBindingsLib(); void *jscLibHandle = nullptr; #endif +#endif #endif JSContextGroupRef mContextGroup; JSGlobalContextRef mContext; diff --git a/include/jsc/JavaScriptWrapper.h b/include/jsc/JavaScriptWrapper.h index 298df7b..50546a5 100644 --- a/include/jsc/JavaScriptWrapper.h +++ b/include/jsc/JavaScriptWrapper.h @@ -33,6 +33,9 @@ rtError jsToRt(JSContextRef context, JSValueRef value, rtValue &result, JSValueRef *exception); JSValueRef rtToJs(JSContextRef context, const rtValue &rtval); +#ifdef UNIT_TEST_BUILD +void clearGlobalWrapperCacheForTests(); +#endif class JSObjectWrapper: public jsruntime::RefCounted, public rtJSCWrapperBase { @@ -50,6 +53,7 @@ class JSObjectWrapper: public jsruntime::RefCounted, public rtJSCWrap class JSFunctionWrapper: public jsruntime::RefCounted, public rtJSCWrapperBase { +private: size_t hash() override { return mHash; } void setHash(size_t hash) override { UNUSED_PARAM(hash); } rtError Send(int numArgs, const rtValue* args, rtValue* result) override; diff --git a/include/jsc/PlayerEventHandler.h b/include/jsc/PlayerEventHandler.h index c88a035..578e4f7 100755 --- a/include/jsc/PlayerEventHandler.h +++ b/include/jsc/PlayerEventHandler.h @@ -41,8 +41,13 @@ class PlayerEventHandler : public AAMPEventObjectListener void removeEventListener(AAMPEventType type, JSObjectRef callback); void removeAllEventListeners(); void Event(const AAMPEventPtr& e); +#ifdef UNIT_TEST_BUILD + void sendEvent(AAMPEventType type, JSObjectRef event); +#endif private: +#ifndef UNIT_TEST_BUILD void sendEvent(AAMPEventType type, JSObjectRef event); +#endif JSContextRef mContext; PlayerInstanceAAMP* mPlayer; std::map> mEventListeners; diff --git a/include/jsc/PlayerWrapper.h b/include/jsc/PlayerWrapper.h index 433f9aa..99b9b58 100644 --- a/include/jsc/PlayerWrapper.h +++ b/include/jsc/PlayerWrapper.h @@ -44,12 +44,63 @@ struct PlayerWrapper JSGlobalContextRef ctx; PlayerInstanceAAMP* mPlayer; +#ifdef UNIT_TEST_BUILD + PlayerEventHandler* mPlayerEventHandler; +#endif + private: JSObjectRef getCallbackForAdId(std::string id); std::map mPromiseCallbacks; +#ifndef UNIT_TEST_BUILD PlayerEventHandler* mPlayerEventHandler; +#endif }; void initializePlayer(JSGlobalContextRef context); void deinitializePlayer(JSGlobalContextRef context); + +#ifdef UNIT_TEST_BUILD +std::vector JSStringArrayToCStringArray(JSContextRef context, JSValueRef arrayRef); + +JSValueRef AAMPMediaPlayerJS_initConfig(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_load(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setVolume(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_addEventListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_removeEventListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_subscribeResponseHeaders(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setSubscribedTags(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_addCustomHTTPHeader(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_removeCustomHTTPHeader(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setClosedCaptionStatus(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setVideoMute(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_play(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_detach(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_pause(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_release(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_stop(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_seek(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getAudioTrackInfo(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getTextTrackInfo(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getDurationSec(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getCurrentPosition(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getAudioTrack(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getTextTrack(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getVolume(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setAudioLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setPlaybackRate(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setVideoRect(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setVideoZoom(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setPreferredAudioLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setPreferredTextLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setTextStyleOptions(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setAuxiliaryLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_xreSupportedTune(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); + +JSValueRef AAMPMediaPlayerJS_getAvailableAudioTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getAvailableTextTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getVideoRectangle(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setAlternateContent(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_notifyReservationCompletion(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +#endif + #endif diff --git a/include/rtWebSocket.h b/include/rtWebSocket.h index e0fc057..40133b9 100644 --- a/include/rtWebSocket.h +++ b/include/rtWebSocket.h @@ -106,3 +106,4 @@ class rtWebSocket : public rtObject }; #endif //RT_WEB_SOCKET_H + diff --git a/src/jsc/JavaScriptWrapper.cpp b/src/jsc/JavaScriptWrapper.cpp index c363973..e64eed2 100644 --- a/src/jsc/JavaScriptWrapper.cpp +++ b/src/jsc/JavaScriptWrapper.cpp @@ -969,3 +969,12 @@ rtError JSFunctionWrapper::Send(int numArgs, const rtValue* args, rtValue* resul return RT_OK; } } + +#ifdef UNIT_TEST_BUILD + +void clearGlobalWrapperCacheForTests() +{ + assertIsMainThread(); + globalWrapperCache.clear(); +} +#endif diff --git a/src/jsc/PlayerWrapper.cpp b/src/jsc/PlayerWrapper.cpp index e1a748c..77dfe01 100644 --- a/src/jsc/PlayerWrapper.cpp +++ b/src/jsc/PlayerWrapper.cpp @@ -1128,7 +1128,11 @@ JSValueRef AAMPMediaPlayerJS_setVideoZoom (JSContextRef ctx, JSObjectRef functio return JSValueMakeUndefined(ctx); } +#ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_getAvailableAudioTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else static JSValueRef AAMPMediaPlayerJS_getAvailableAudioTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) @@ -1163,7 +1167,11 @@ static JSValueRef AAMPMediaPlayerJS_getAvailableAudioTracks(JSContextRef ctx, JS * @param[out] exception pointer to a JSValueRef in which to return an exception, if any * @retval JSValue that is the function's return value */ + #ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_getAvailableTextTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else static JSValueRef AAMPMediaPlayerJS_getAvailableTextTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) @@ -1198,7 +1206,11 @@ static JSValueRef AAMPMediaPlayerJS_getAvailableTextTracks(JSContextRef ctx, JSO * @param[out] exception pointer to a JSValueRef in which to return an exception, if any * @retval JSValue that is the function's return value */ +#ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_getVideoRectangle(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else static JSValueRef AAMPMediaPlayerJS_getVideoRectangle(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) @@ -1221,7 +1233,11 @@ static JSValueRef AAMPMediaPlayerJS_getVideoRectangle(JSContextRef ctx, JSObject * @param[out] exception pointer to a JSValueRef in which to return an exception, if any * @retval JSValue that is the function's return value */ -static JSValueRef AAMPMediaPlayerJS_setAlternateContent(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_setAlternateContent(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else +static JSValueRef AAMPMediaPlayerJS_setAlternateContent(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) @@ -1405,7 +1421,11 @@ JSValueRef AAMPMediaPlayerJS_setPreferredTextLanguage(JSContextRef ctx, JSObject return JSValueMakeUndefined(ctx); } +#ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_notifyReservationCompletion(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else static JSValueRef AAMPMediaPlayerJS_notifyReservationCompletion(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) @@ -1458,7 +1478,11 @@ JSValueRef AAMPMediaPlayerJS_setTextStyleOptions(JSContextRef ctx, JSObjectRef f return JSValueMakeUndefined(ctx); } +#ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_setAuxiliaryLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else static JSValueRef AAMPMediaPlayerJS_setAuxiliaryLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) diff --git a/src/jsc/jsc_lib/jsc_lib.cpp b/src/jsc/jsc_lib/jsc_lib.cpp index 8972922..b759135 100644 --- a/src/jsc/jsc_lib/jsc_lib.cpp +++ b/src/jsc/jsc_lib/jsc_lib.cpp @@ -65,6 +65,7 @@ const GlobalObjectMethodTable s_globalObjectMethodTableMadan = { nullptr, // deriveShadowRealmGlobalObject }; +#ifndef USE_JSCLIB_MOCK struct MemoryStruct { MemoryStruct() @@ -98,6 +99,7 @@ struct MemoryStruct char* contentsBuffer; size_t readSize; }; +#endif // !USE_JSCLIB_MOCK static size_t CallbackHeader(void *contents, size_t size, size_t nmemb, void *userp) { @@ -140,6 +142,11 @@ bool downloadFile(std::string& url, MemoryStruct& chunk) bool ret = false; CURL *curl; CURLcode res; +#ifdef USE_JSCLIB_MOCK + if (MockControl::simulate_curl_init_failure) + curl = nullptr; + else +#endif curl = curl_easy_init(); if (curl) { @@ -178,6 +185,116 @@ bool downloadFile(std::string& url, MemoryStruct& chunk) } return ret; } + +#ifdef USE_JSCLIB_MOCK +// Non-static versions for testing +UChar pathSeparator() +{ +#if OS(WINDOWS) + return '\\'; +#else + return '/'; +#endif +} + +bool isAbsolutePath(StringView path) +{ +#if OS(WINDOWS) + // Just look for local drives like C:\. + return path.length() > 2 && isASCIIAlpha(path[0]) && path[1] == ':' && (path[2] == '\\' || path[2] == '/'); +#else + return path.startsWith('/'); +#endif +} + +bool isDottedRelativePath(StringView path) +{ +#if OS(WINDOWS) + auto length = path.length(); + if (length < 2 || path[0] != '.') + return false; + + if (path[1] == '/' || path[1] == '\\') + return true; + + return length > 2 && path[1] == '.' && (path[2] == '/' || path[2] == '\\'); +#else + return path.startsWith("./"_s) || path.startsWith("../"_s); +#endif +} + +void convertShebangToJSCommentWrapper(char* buffer, size_t size) +{ + if (size >= 2) { + if (buffer[0] == '#' && buffer[1] == '!') + buffer[0] = buffer[1] = '/'; + } +} + +bool fetchScriptFromLocalFileSystemWrapper(const char* fileName, char** outBuffer, size_t* outSize) +{ + String fileNameStr = String::fromUTF8(fileName); + Vector buffer; + FILE* f = fopen(fileName, "rb"); + if (!f) + return false; + +#ifdef USE_JSCLIB_MOCK + if (MockControl::simulate_fseek_failure) { + fclose(f); + return false; + } +#endif + if (fseek(f, 0, SEEK_END) == -1) { + fclose(f); + return false; + } +#ifdef USE_JSCLIB_MOCK + if (MockControl::simulate_ftell_failure) { + fclose(f); + return false; + } +#endif + long bufferCapacity = ftell(f); + if (bufferCapacity == -1) { + fclose(f); + return false; + } + if (fseek(f, 0, SEEK_SET) == -1) { + fclose(f); + return false; + } + buffer.resize(bufferCapacity); +#ifdef USE_JSCLIB_MOCK + size_t readSize; + if (MockControl::simulate_fread_short) { + readSize = 0; // Simulate partial/failed read + } else { + readSize = fread(buffer.data(), 1, bufferCapacity, f); + } +#else + size_t readSize = fread(buffer.data(), 1, bufferCapacity, f); +#endif + fclose(f); + + if (readSize != static_cast(bufferCapacity)) + return false; + + // Convert shebang + if (buffer.size() >= 2) { + if (buffer[0] == '#' && buffer[1] == '!') + buffer[0] = buffer[1] = '/'; + } + + *outSize = buffer.size(); + *outBuffer = (char*)malloc(*outSize + 1); + memcpy(*outBuffer, buffer.data(), *outSize); + (*outBuffer)[*outSize] = 0; + return true; +} + +#endif // USE_JSCLIB_MOCK + template class GlobalObject; @@ -225,13 +342,7 @@ static inline String stringFromUTF(const Vector& utf8) return String::fromUTF8WithLatin1Fallback(utf8.data(), utf8.size()); } -/* -Copyright (C) 1999-2000 Harri Porten ([porten@kde.org](mailto:porten@kde.org)) -Copyright (C) 2004-2020 Apple Inc. All rights reserved. -Copyright (C) 2006 Bjoern Graf ([bjoern.graf@gmail.com](mailto:bjoern.graf@gmail.com)) -Licensed under the LGPL License, Version 2.0 -*/ - +#ifndef USE_JSCLIB_MOCK static UChar pathSeparator() { #if OS(WINDOWS) @@ -240,6 +351,7 @@ static UChar pathSeparator() return '/'; #endif } +#endif // !USE_JSCLIB_MOCK static URL currentWorkingDirectory() { @@ -285,6 +397,7 @@ static URL currentWorkingDirectory() // FIXME: We may wish to support module specifiers beginning with a (back)slash on Windows. We could either: // - align with V8 and SM: treat '/foo' as './foo' // - align with PowerShell: treat '/foo' as 'C:/foo' +#ifndef USE_JSCLIB_MOCK static bool isAbsolutePath(StringView path) { #if OS(WINDOWS) @@ -310,6 +423,7 @@ static bool isDottedRelativePath(StringView path) return path.startsWith("./"_s) || path.startsWith("../"_s); #endif } +#endif // !USE_JSCLIB_MOCK static URL absoluteFileURL(const String& fileName) { @@ -403,6 +517,97 @@ static bool fetchScriptFromLocalFileSystem(const String& fileName, Vector& return true; } +#ifdef USE_JSCLIB_MOCK +// Wrapper functions for testing - must be after static function definitions +String stringFromUTFWrapper(const char* data, size_t size) +{ + Vector vec; + vec.resize(size); + memcpy(vec.data(), data, size); + return stringFromUTF(vec); +} + +bool fillBufferWithContentsOfFileWrapper(const char* fileName, char** outBuffer, size_t* outSize) +{ + String fileNameStr = String::fromUTF8(fileName); + Vector buffer; + + if (!fillBufferWithContentsOfFile(fileNameStr, buffer)) + return false; + + *outSize = buffer.size(); + *outBuffer = (char*)malloc(*outSize + 1); + memcpy(*outBuffer, buffer.data(), *outSize); + (*outBuffer)[*outSize] = 0; + return true; +} + +bool absoluteFileURLWrapper(const char* fileName, char** outURL, size_t* outSize) +{ + String fileNameStr = String::fromUTF8(fileName); + URL url = absoluteFileURL(fileNameStr); + + if (!url.isValid()) + return false; + + String urlString = url.string(); + CString utf8 = urlString.utf8(); + *outSize = utf8.length(); + *outURL = (char*)malloc(*outSize + 1); + memcpy(*outURL, utf8.data(), *outSize); + (*outURL)[*outSize] = 0; + return true; +} + +bool fetchScriptFromLocalFileSystemVectorWrapper(const char* fileName, char** outBuffer, size_t* outSize) +{ + String fileNameStr = String::fromUTF8(fileName); + Vector buffer; + + if (!fetchScriptFromLocalFileSystem(fileNameStr, buffer)) + return false; + + *outSize = buffer.size(); + *outBuffer = (char*)malloc(*outSize + 1); + memcpy(*outBuffer, buffer.data(), *outSize); + (*outBuffer)[*outSize] = 0; + return true; +} + +bool fillBufferWithContentsOfFileUint8Wrapper(const char* fileName, unsigned char** outBuffer, size_t* outSize) +{ + String fileNameStr = String::fromUTF8(fileName); + RefPtr result = fillBufferWithContentsOfFile(fileNameStr); + + if (!result) { + *outBuffer = nullptr; + *outSize = 0; + return false; + } + + *outSize = result->byteLength(); + *outBuffer = (unsigned char*)malloc(*outSize); + memcpy(*outBuffer, result->data(), *outSize); + return true; +} + +bool currentWorkingDirectoryWrapper(char** outPath, size_t* outSize) +{ + URL cwd = currentWorkingDirectory(); + + if (!cwd.isValid()) + return false; + + String cwdString = cwd.string(); + CString utf8 = cwdString.utf8(); + *outSize = utf8.length(); + *outPath = (char*)malloc(*outSize + 1); + memcpy(*outPath, utf8.data(), *outSize); + (*outPath)[*outSize] = 0; + return true; +} +#endif // USE_JSCLIB_MOCK + class ShellSourceProvider final : public StringSourceProvider { public: static Ref create(const String& source, const SourceOrigin& sourceOrigin, String&& sourceURL, const TextPosition& startPosition, SourceProviderSourceType sourceType) @@ -854,3 +1059,4 @@ void functionLoadModule(JSGlobalContextRef ref, JSObjectRef globalObjectRef, cha //promise->then(exec, nullptr, errorHandler); promise->then(toJS(ref), fulfillHandler, rejectHandler); } + diff --git a/src/jsc/jsc_lib/jsc_lib.h b/src/jsc/jsc_lib/jsc_lib.h index b9f5ccd..6fa9d8e 100644 --- a/src/jsc/jsc_lib/jsc_lib.h +++ b/src/jsc/jsc_lib/jsc_lib.h @@ -111,4 +111,25 @@ #define PATH_MAX 4096 #endif -void functionLoadModule(JSGlobalContextRef ref, JSObjectRef globalObjectRef, char *buffer, int len, char* name); \ No newline at end of file +void functionLoadModule(JSGlobalContextRef ref, JSObjectRef globalObjectRef, char *buffer, int len, char* name); + +#ifdef USE_JSCLIB_MOCK + +typedef unsigned short UChar; +UChar pathSeparator(); +bool isAbsolutePath(JSC::StringView path); +bool isDottedRelativePath(JSC::StringView path); +void convertShebangToJSCommentWrapper(char* buffer, size_t size); +bool fetchScriptFromLocalFileSystemWrapper(const char* fileName, char** outBuffer, size_t* outSize); +JSC::String stringFromUTFWrapper(const char* data, size_t size); +bool fillBufferWithContentsOfFileWrapper(const char* fileName, char** outBuffer, size_t* outSize); +bool absoluteFileURLWrapper(const char* fileName, char** outURL, size_t* outSize); +bool fetchScriptFromLocalFileSystemVectorWrapper(const char* fileName, char** outBuffer, size_t* outSize); +bool fillBufferWithContentsOfFileUint8Wrapper(const char* fileName, unsigned char** outBuffer, size_t* outSize); +bool currentWorkingDirectoryWrapper(char** outPath, size_t* outSize); + + +struct MemoryStruct; + +bool downloadFile(std::string& url, MemoryStruct& chunk); +#endif