From e6cf01356e3336dc4f0717a391d9067693a418c1 Mon Sep 17 00:00:00 2001 From: tsepez Date: Wed, 18 Jan 2017 14:38:18 -0800 Subject: Tidy FXJS_V8, backfill tests. Move checks performed as part of JS_Value's object and array handling back into FXJS, to ease removal of JS_Value in the future. Remove some convenience routines in FXJS for objects, to shrink API to be covered during testing. Change some naming (number => double, string => widestring) to make it clearer when there is a C++ type involved. BUG= Review-Url: https://codereview.chromium.org/2637503002 --- fpdfsdk/javascript/Document.cpp | 30 +++++---- fpdfsdk/javascript/JS_Value.cpp | 27 ++++---- fpdfsdk/javascript/global.cpp | 52 +++++++-------- fxjs/fxjs_v8.cpp | 90 +++++--------------------- fxjs/fxjs_v8.h | 34 +++------- fxjs/fxjs_v8_embeddertest.cpp | 139 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 221 insertions(+), 151 deletions(-) diff --git a/fpdfsdk/javascript/Document.cpp b/fpdfsdk/javascript/Document.cpp index 79d68ec3a7..4bf1afd5a3 100644 --- a/fpdfsdk/javascript/Document.cpp +++ b/fpdfsdk/javascript/Document.cpp @@ -801,15 +801,18 @@ bool Document::info(IJS_Context* cc, CJS_Runtime* pRuntime = pContext->GetJSRuntime(); v8::Local pObj = pRuntime->NewFxDynamicObj(-1); - pRuntime->PutObjectString(pObj, L"Author", cwAuthor); - pRuntime->PutObjectString(pObj, L"Title", cwTitle); - pRuntime->PutObjectString(pObj, L"Subject", cwSubject); - pRuntime->PutObjectString(pObj, L"Keywords", cwKeywords); - pRuntime->PutObjectString(pObj, L"Creator", cwCreator); - pRuntime->PutObjectString(pObj, L"Producer", cwProducer); - pRuntime->PutObjectString(pObj, L"CreationDate", cwCreationDate); - pRuntime->PutObjectString(pObj, L"ModDate", cwModDate); - pRuntime->PutObjectString(pObj, L"Trapped", cwTrapped); + pRuntime->PutObjectProperty(pObj, L"Author", pRuntime->NewString(cwAuthor)); + pRuntime->PutObjectProperty(pObj, L"Title", pRuntime->NewString(cwTitle)); + pRuntime->PutObjectProperty(pObj, L"Subject", pRuntime->NewString(cwSubject)); + pRuntime->PutObjectProperty(pObj, L"Keywords", + pRuntime->NewString(cwKeywords)); + pRuntime->PutObjectProperty(pObj, L"Creator", pRuntime->NewString(cwCreator)); + pRuntime->PutObjectProperty(pObj, L"Producer", + pRuntime->NewString(cwProducer)); + pRuntime->PutObjectProperty(pObj, L"CreationDate", + pRuntime->NewString(cwCreationDate)); + pRuntime->PutObjectProperty(pObj, L"ModDate", pRuntime->NewString(cwModDate)); + pRuntime->PutObjectProperty(pObj, L"Trapped", pRuntime->NewString(cwTrapped)); // It's to be compatible to non-standard info dictionary. for (const auto& it : *pDictionary) { @@ -817,11 +820,14 @@ bool Document::info(IJS_Context* cc, CPDF_Object* pValueObj = it.second.get(); CFX_WideString wsKey = CFX_WideString::FromUTF8(bsKey.AsStringC()); if (pValueObj->IsString() || pValueObj->IsName()) { - pRuntime->PutObjectString(pObj, wsKey, pValueObj->GetUnicodeText()); + pRuntime->PutObjectProperty( + pObj, wsKey, pRuntime->NewString(pValueObj->GetUnicodeText())); } else if (pValueObj->IsNumber()) { - pRuntime->PutObjectNumber(pObj, wsKey, (float)pValueObj->GetNumber()); + pRuntime->PutObjectProperty(pObj, wsKey, + pRuntime->NewNumber(pValueObj->GetNumber())); } else if (pValueObj->IsBoolean()) { - pRuntime->PutObjectBoolean(pObj, wsKey, !!pValueObj->GetInteger()); + pRuntime->PutObjectProperty( + pObj, wsKey, pRuntime->NewBoolean(!!pValueObj->GetInteger())); } } vp << pObj; diff --git a/fpdfsdk/javascript/JS_Value.cpp b/fpdfsdk/javascript/JS_Value.cpp index c99affbede..7900914a8e 100644 --- a/fpdfsdk/javascript/JS_Value.cpp +++ b/fpdfsdk/javascript/JS_Value.cpp @@ -88,7 +88,7 @@ bool CJS_Value::ToBool(CJS_Runtime* pRuntime) const { } double CJS_Value::ToDouble(CJS_Runtime* pRuntime) const { - return pRuntime->ToNumber(m_pValue); + return pRuntime->ToDouble(m_pValue); } float CJS_Value::ToFloat(CJS_Runtime* pRuntime) const { @@ -105,7 +105,7 @@ v8::Local CJS_Value::ToV8Object(CJS_Runtime* pRuntime) const { } CFX_WideString CJS_Value::ToCFXWideString(CJS_Runtime* pRuntime) const { - return pRuntime->ToString(m_pValue); + return pRuntime->ToWideString(m_pValue); } CFX_ByteString CJS_Value::ToCFXByteString(CJS_Runtime* pRuntime) const { @@ -117,9 +117,7 @@ v8::Local CJS_Value::ToV8Value(CJS_Runtime* pRuntime) const { } v8::Local CJS_Value::ToV8Array(CJS_Runtime* pRuntime) const { - if (IsArrayObject()) - return v8::Local::Cast(pRuntime->ToObject(m_pValue)); - return v8::Local(); + return pRuntime->ToArray(m_pValue); } void CJS_Value::SetNull(CJS_Runtime* pRuntime) { @@ -360,7 +358,7 @@ CJS_Date::CJS_Date(CJS_Runtime* pRuntime, CJS_Date::~CJS_Date() {} bool CJS_Date::IsValidDate(CJS_Runtime* pRuntime) const { - return !m_pDate.IsEmpty() && !JS_PortIsNan(pRuntime->ToNumber(m_pDate)); + return !m_pDate.IsEmpty() && !JS_PortIsNan(pRuntime->ToDouble(m_pDate)); } void CJS_Date::Attach(v8::Local pDate) { @@ -371,7 +369,7 @@ int CJS_Date::GetYear(CJS_Runtime* pRuntime) const { if (!IsValidDate(pRuntime)) return 0; - return JS_GetYearFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate))); + return JS_GetYearFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate))); } void CJS_Date::SetYear(CJS_Runtime* pRuntime, int iYear) { @@ -384,7 +382,7 @@ int CJS_Date::GetMonth(CJS_Runtime* pRuntime) const { if (!IsValidDate(pRuntime)) return 0; - return JS_GetMonthFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate))); + return JS_GetMonthFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate))); } void CJS_Date::SetMonth(CJS_Runtime* pRuntime, int iMonth) { @@ -397,7 +395,7 @@ int CJS_Date::GetDay(CJS_Runtime* pRuntime) const { if (!IsValidDate(pRuntime)) return 0; - return JS_GetDayFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate))); + return JS_GetDayFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate))); } void CJS_Date::SetDay(CJS_Runtime* pRuntime, int iDay) { @@ -410,7 +408,7 @@ int CJS_Date::GetHours(CJS_Runtime* pRuntime) const { if (!IsValidDate(pRuntime)) return 0; - return JS_GetHourFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate))); + return JS_GetHourFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate))); } void CJS_Date::SetHours(CJS_Runtime* pRuntime, int iHours) { @@ -423,7 +421,7 @@ int CJS_Date::GetMinutes(CJS_Runtime* pRuntime) const { if (!IsValidDate(pRuntime)) return 0; - return JS_GetMinFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate))); + return JS_GetMinFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate))); } void CJS_Date::SetMinutes(CJS_Runtime* pRuntime, int minutes) { @@ -436,7 +434,7 @@ int CJS_Date::GetSeconds(CJS_Runtime* pRuntime) const { if (!IsValidDate(pRuntime)) return 0; - return JS_GetSecFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate))); + return JS_GetSecFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate))); } void CJS_Date::SetSeconds(CJS_Runtime* pRuntime, int seconds) { @@ -446,11 +444,12 @@ void CJS_Date::SetSeconds(CJS_Runtime* pRuntime, int seconds) { } double CJS_Date::ToDouble(CJS_Runtime* pRuntime) const { - return !m_pDate.IsEmpty() ? pRuntime->ToNumber(m_pDate) : 0.0; + return !m_pDate.IsEmpty() ? pRuntime->ToDouble(m_pDate) : 0.0; } CFX_WideString CJS_Date::ToString(CJS_Runtime* pRuntime) const { - return !m_pDate.IsEmpty() ? pRuntime->ToString(m_pDate) : CFX_WideString(); + return !m_pDate.IsEmpty() ? pRuntime->ToWideString(m_pDate) + : CFX_WideString(); } v8::Local CJS_Date::ToV8Date(CJS_Runtime* pRuntime) const { diff --git a/fpdfsdk/javascript/global.cpp b/fpdfsdk/javascript/global.cpp index c2d3586874..aca86979ae 100644 --- a/fpdfsdk/javascript/global.cpp +++ b/fpdfsdk/javascript/global.cpp @@ -192,41 +192,41 @@ void JSGlobalAlternate::UpdateGlobalPersistentVariables() { SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::NUMBER, pData->data.dData, false, "", v8::Local(), pData->bPersistent == 1); - pRuntime->PutObjectNumber(m_pJSObject->ToV8Object(), - pData->data.sKey.UTF8Decode(), - pData->data.dData); + pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(), + pData->data.sKey.UTF8Decode(), + pRuntime->NewNumber(pData->data.dData)); break; case JS_GlobalDataType::BOOLEAN: SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::BOOLEAN, 0, - (bool)(pData->data.bData == 1), "", - v8::Local(), pData->bPersistent == 1); - pRuntime->PutObjectBoolean(m_pJSObject->ToV8Object(), - pData->data.sKey.UTF8Decode(), - (bool)(pData->data.bData == 1)); + pData->data.bData == 1, "", v8::Local(), + pData->bPersistent == 1); + pRuntime->PutObjectProperty( + m_pJSObject->ToV8Object(), pData->data.sKey.UTF8Decode(), + pRuntime->NewBoolean(pData->data.bData == 1)); break; case JS_GlobalDataType::STRING: SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::STRING, 0, false, pData->data.sData, v8::Local(), pData->bPersistent == 1); - pRuntime->PutObjectString(m_pJSObject->ToV8Object(), - pData->data.sKey.UTF8Decode(), - pData->data.sData.UTF8Decode()); + pRuntime->PutObjectProperty( + m_pJSObject->ToV8Object(), pData->data.sKey.UTF8Decode(), + pRuntime->NewString(pData->data.sData.UTF8Decode())); break; case JS_GlobalDataType::OBJECT: { v8::Local pObj = pRuntime->NewFxDynamicObj(-1); - PutObjectProperty(pObj, &pData->data); SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::OBJECT, 0, false, "", pObj, pData->bPersistent == 1); - pRuntime->PutObjectObject(m_pJSObject->ToV8Object(), - pData->data.sKey.UTF8Decode(), pObj); + pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(), + pData->data.sKey.UTF8Decode(), pObj); } break; case JS_GlobalDataType::NULLOBJ: SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::NULLOBJ, 0, false, "", v8::Local(), pData->bPersistent == 1); - pRuntime->PutObjectNull(m_pJSObject->ToV8Object(), - pData->data.sKey.UTF8Decode()); + pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(), + pData->data.sKey.UTF8Decode(), + pRuntime->NewNull()); break; } } @@ -282,7 +282,7 @@ void JSGlobalAlternate::ObjectToArray(IJS_Context* cc, CJS_KeyValue* pObjElement = new CJS_KeyValue; pObjElement->nType = JS_GlobalDataType::NUMBER; pObjElement->sKey = sKey; - pObjElement->dData = pRuntime->ToNumber(v); + pObjElement->dData = pRuntime->ToDouble(v); array.Add(pObjElement); } break; case CJS_Value::VT_boolean: { @@ -329,24 +329,26 @@ void JSGlobalAlternate::PutObjectProperty(v8::Local pObj, CJS_KeyValue* pObjData = pData->objData.GetAt(i); switch (pObjData->nType) { case JS_GlobalDataType::NUMBER: - pRuntime->PutObjectNumber(pObj, pObjData->sKey.UTF8Decode(), - pObjData->dData); + pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(), + pRuntime->NewNumber(pObjData->dData)); break; case JS_GlobalDataType::BOOLEAN: - pRuntime->PutObjectBoolean(pObj, pObjData->sKey.UTF8Decode(), - pObjData->bData == 1); + pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(), + pRuntime->NewBoolean(pObjData->bData == 1)); break; case JS_GlobalDataType::STRING: - pRuntime->PutObjectString(pObj, pObjData->sKey.UTF8Decode(), - pObjData->sData.UTF8Decode()); + pRuntime->PutObjectProperty( + pObj, pObjData->sKey.UTF8Decode(), + pRuntime->NewString(pObjData->sData.UTF8Decode())); break; case JS_GlobalDataType::OBJECT: { v8::Local pNewObj = pRuntime->NewFxDynamicObj(-1); PutObjectProperty(pNewObj, pObjData); - pRuntime->PutObjectObject(pObj, pObjData->sKey.UTF8Decode(), pNewObj); + pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(), pNewObj); } break; case JS_GlobalDataType::NULLOBJ: - pRuntime->PutObjectNull(pObj, pObjData->sKey.UTF8Decode()); + pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(), + pRuntime->NewNull()); break; } } diff --git a/fxjs/fxjs_v8.cpp b/fxjs/fxjs_v8.cpp index 5ce8c47569..c96cc1f0e0 100644 --- a/fxjs/fxjs_v8.cpp +++ b/fxjs/fxjs_v8.cpp @@ -596,79 +596,21 @@ std::vector CFXJS_Engine::GetObjectPropertyNames( std::vector result; for (uint32_t i = 0; i < val->Length(); ++i) { - result.push_back(ToString(val->Get(context, i).ToLocalChecked())); + result.push_back(ToWideString(val->Get(context, i).ToLocalChecked())); } return result; } -void CFXJS_Engine::PutObjectString(v8::Local pObj, - const CFX_WideString& wsPropertyName, - const CFX_WideString& wsValue) { - if (pObj.IsEmpty()) - return; - pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName), - WSToJSString(wsValue)) - .FromJust(); -} - -void CFXJS_Engine::PutObjectNumber(v8::Local pObj, - const CFX_WideString& wsPropertyName, - int nValue) { - if (pObj.IsEmpty()) - return; - pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName), - v8::Int32::New(m_isolate, nValue)) - .FromJust(); -} - -void CFXJS_Engine::PutObjectNumber(v8::Local pObj, - const CFX_WideString& wsPropertyName, - float fValue) { - if (pObj.IsEmpty()) - return; - pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName), - v8::Number::New(m_isolate, (double)fValue)) - .FromJust(); -} - -void CFXJS_Engine::PutObjectNumber(v8::Local pObj, - const CFX_WideString& wsPropertyName, - double dValue) { - if (pObj.IsEmpty()) - return; - pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName), - v8::Number::New(m_isolate, (double)dValue)) - .FromJust(); -} - -void CFXJS_Engine::PutObjectBoolean(v8::Local pObj, - const CFX_WideString& wsPropertyName, - bool bValue) { - if (pObj.IsEmpty()) - return; - pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName), - v8::Boolean::New(m_isolate, bValue)) - .FromJust(); -} - -void CFXJS_Engine::PutObjectObject(v8::Local pObj, - const CFX_WideString& wsPropertyName, - v8::Local pPut) { +void CFXJS_Engine::PutObjectProperty(v8::Local pObj, + const CFX_WideString& wsPropertyName, + v8::Local pPut) { if (pObj.IsEmpty()) return; pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName), pPut) .FromJust(); } -void CFXJS_Engine::PutObjectNull(v8::Local pObj, - const CFX_WideString& wsPropertyName) { - if (pObj.IsEmpty()) - return; - pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName), - v8::Local()) - .FromJust(); -} v8::Local CFXJS_Engine::NewArray() { return v8::Array::New(m_isolate); @@ -724,8 +666,8 @@ v8::Local CFXJS_Engine::NewBoolean(bool b) { return v8::Boolean::New(m_isolate, b); } -v8::Local CFXJS_Engine::NewString(const wchar_t* str) { - return WSToJSString(str); +v8::Local CFXJS_Engine::NewString(const CFX_WideString& str) { + return WSToJSString(str.c_str()); } v8::Local CFXJS_Engine::NewNull() { @@ -752,30 +694,30 @@ bool CFXJS_Engine::ToBoolean(v8::Local pValue) { return pValue->ToBoolean(context).ToLocalChecked()->Value(); } -double CFXJS_Engine::ToNumber(v8::Local pValue) { +double CFXJS_Engine::ToDouble(v8::Local pValue) { if (pValue.IsEmpty()) return 0.0; v8::Local context = m_isolate->GetCurrentContext(); return pValue->ToNumber(context).ToLocalChecked()->Value(); } -v8::Local CFXJS_Engine::ToObject(v8::Local pValue) { +CFX_WideString CFXJS_Engine::ToWideString(v8::Local pValue) { if (pValue.IsEmpty()) - return v8::Local(); + return CFX_WideString(); v8::Local context = m_isolate->GetCurrentContext(); - return pValue->ToObject(context).ToLocalChecked(); + v8::String::Utf8Value s(pValue->ToString(context).ToLocalChecked()); + return CFX_WideString::FromUTF8(CFX_ByteStringC(*s, s.length())); } -CFX_WideString CFXJS_Engine::ToString(v8::Local pValue) { - if (pValue.IsEmpty()) - return L""; +v8::Local CFXJS_Engine::ToObject(v8::Local pValue) { + if (pValue.IsEmpty() || !pValue->IsObject()) + return v8::Local(); v8::Local context = m_isolate->GetCurrentContext(); - v8::String::Utf8Value s(pValue->ToString(context).ToLocalChecked()); - return CFX_WideString::FromUTF8(CFX_ByteStringC(*s, s.length())); + return pValue->ToObject(context).ToLocalChecked(); } v8::Local CFXJS_Engine::ToArray(v8::Local pValue) { - if (pValue.IsEmpty()) + if (pValue.IsEmpty() || !pValue->IsArray()) return v8::Local(); v8::Local context = m_isolate->GetCurrentContext(); return v8::Local::Cast(pValue->ToObject(context).ToLocalChecked()); diff --git a/fxjs/fxjs_v8.h b/fxjs/fxjs_v8.h index ba729626f2..6cf3ca578e 100644 --- a/fxjs/fxjs_v8.h +++ b/fxjs/fxjs_v8.h @@ -176,6 +176,7 @@ class CFXJS_Engine { v8::Local NewLocalContext(); v8::Local GetPersistentContext(); + v8::Local GetThisObj(); v8::Local NewNull(); v8::Local NewArray(); @@ -183,18 +184,18 @@ class CFXJS_Engine { v8::Local NewNumber(double number); v8::Local NewNumber(float number); v8::Local NewBoolean(bool b); - v8::Local NewString(const wchar_t* str); + v8::Local NewString(const CFX_WideString& str); v8::Local NewDate(double d); v8::Local NewFxDynamicObj(int nObjDefnID, bool bStatic = false); - v8::Local GetThisObj(); int ToInt32(v8::Local pValue); bool ToBoolean(v8::Local pValue); - double ToNumber(v8::Local pValue); - CFX_WideString ToString(v8::Local pValue); + double ToDouble(v8::Local pValue); + CFX_WideString ToWideString(v8::Local pValue); v8::Local ToObject(v8::Local pValue); v8::Local ToArray(v8::Local pValue); + // Arrays. unsigned GetArrayLength(v8::Local pArray); v8::Local GetArrayElement(v8::Local pArray, unsigned index); @@ -202,31 +203,14 @@ class CFXJS_Engine { unsigned index, v8::Local pValue); + // Objects. std::vector GetObjectPropertyNames( v8::Local pObj); v8::Local GetObjectProperty(v8::Local pObj, const CFX_WideString& PropertyName); - - void PutObjectString(v8::Local pObj, - const CFX_WideString& wsPropertyName, - const CFX_WideString& wsValue); - void PutObjectNumber(v8::Local pObj, - const CFX_WideString& PropertyName, - int nValue); - void PutObjectNumber(v8::Local pObj, - const CFX_WideString& PropertyName, - float fValue); - void PutObjectNumber(v8::Local pObj, - const CFX_WideString& PropertyName, - double dValue); - void PutObjectBoolean(v8::Local pObj, - const CFX_WideString& PropertyName, - bool bValue); - void PutObjectObject(v8::Local pObj, - const CFX_WideString& PropertyName, - v8::Local pPut); - void PutObjectNull(v8::Local pObj, - const CFX_WideString& PropertyName); + void PutObjectProperty(v8::Local pObj, + const CFX_WideString& PropertyName, + v8::Local pValue); // Native object binding. void SetObjectPrivate(v8::Local pObj, void* p); diff --git a/fxjs/fxjs_v8_embeddertest.cpp b/fxjs/fxjs_v8_embeddertest.cpp index a877a36e56..4d05a20bf9 100644 --- a/fxjs/fxjs_v8_embeddertest.cpp +++ b/fxjs/fxjs_v8_embeddertest.cpp @@ -28,7 +28,7 @@ class FXJSV8EmbedderTest : public JSEmbedderTest { v8::Local This = engine()->GetThisObj(); v8::Local fred = engine()->GetObjectProperty(This, L"fred"); EXPECT_TRUE(fred->IsNumber()); - EXPECT_EQ(expected, engine()->ToNumber(fred)); + EXPECT_EQ(expected, engine()->ToDouble(fred)); } }; @@ -74,3 +74,140 @@ TEST_F(FXJSV8EmbedderTest, MultipleEngines) { engine2.ReleaseEngine(); CheckAssignmentInCurrentContext(kExpected0); } + +TEST_F(FXJSV8EmbedderTest, EmptyLocal) { + v8::Isolate::Scope isolate_scope(isolate()); + v8::HandleScope handle_scope(isolate()); + v8::Context::Scope context_scope(GetV8Context()); + + v8::Local empty; + EXPECT_FALSE(engine()->ToBoolean(empty)); + EXPECT_EQ(0, engine()->ToInt32(empty)); + EXPECT_EQ(0.0, engine()->ToDouble(empty)); + EXPECT_EQ(L"", engine()->ToWideString(empty)); + EXPECT_TRUE(engine()->ToObject(empty).IsEmpty()); + EXPECT_TRUE(engine()->ToArray(empty).IsEmpty()); +} + +TEST_F(FXJSV8EmbedderTest, NewNull) { + v8::Isolate::Scope isolate_scope(isolate()); + v8::HandleScope handle_scope(isolate()); + v8::Context::Scope context_scope(GetV8Context()); + + auto nullz = engine()->NewNull(); + EXPECT_FALSE(engine()->ToBoolean(nullz)); + EXPECT_EQ(0, engine()->ToInt32(nullz)); + EXPECT_EQ(0.0, engine()->ToDouble(nullz)); + EXPECT_EQ(L"", engine()->ToWideString(nullz)); + EXPECT_TRUE(engine()->ToObject(nullz).IsEmpty()); + EXPECT_TRUE(engine()->ToArray(nullz).IsEmpty()); +} + +TEST_F(FXJSV8EmbedderTest, NewBoolean) { + v8::Isolate::Scope isolate_scope(isolate()); + v8::HandleScope handle_scope(isolate()); + v8::Context::Scope context_scope(GetV8Context()); + + auto boolz = engine()->NewBoolean(true); + EXPECT_TRUE(engine()->ToBoolean(boolz)); + EXPECT_EQ(1, engine()->ToInt32(boolz)); + EXPECT_EQ(1.0, engine()->ToDouble(boolz)); + EXPECT_EQ(L"true", engine()->ToWideString(boolz)); + EXPECT_TRUE(engine()->ToObject(boolz).IsEmpty()); + EXPECT_TRUE(engine()->ToArray(boolz).IsEmpty()); +} + +TEST_F(FXJSV8EmbedderTest, NewNumber) { + v8::Isolate::Scope isolate_scope(isolate()); + v8::HandleScope handle_scope(isolate()); + v8::Context::Scope context_scope(GetV8Context()); + + auto num = engine()->NewNumber(42.1); + EXPECT_TRUE(engine()->ToBoolean(num)); + EXPECT_EQ(42, engine()->ToInt32(num)); + EXPECT_EQ(42.1, engine()->ToDouble(num)); + EXPECT_EQ(L"42.1", engine()->ToWideString(num)); + EXPECT_TRUE(engine()->ToObject(num).IsEmpty()); + EXPECT_TRUE(engine()->ToArray(num).IsEmpty()); +} + +TEST_F(FXJSV8EmbedderTest, NewString) { + v8::Isolate::Scope isolate_scope(isolate()); + v8::HandleScope handle_scope(isolate()); + v8::Context::Scope context_scope(GetV8Context()); + + auto str = engine()->NewString(L"123"); + EXPECT_TRUE(engine()->ToBoolean(str)); + EXPECT_EQ(123, engine()->ToInt32(str)); + EXPECT_EQ(123, engine()->ToDouble(str)); + EXPECT_EQ(L"123", engine()->ToWideString(str)); + EXPECT_TRUE(engine()->ToObject(str).IsEmpty()); + EXPECT_TRUE(engine()->ToArray(str).IsEmpty()); +} + +TEST_F(FXJSV8EmbedderTest, NewDate) { + v8::Isolate::Scope isolate_scope(isolate()); + v8::HandleScope handle_scope(isolate()); + v8::Context::Scope context_scope(GetV8Context()); + + auto date = engine()->NewDate(1111111111); + EXPECT_TRUE(engine()->ToBoolean(date)); + EXPECT_EQ(1111111111, engine()->ToInt32(date)); + EXPECT_EQ(1111111111.0, engine()->ToDouble(date)); + EXPECT_NE(L"", engine()->ToWideString(date)); // exact format varies. + EXPECT_TRUE(engine()->ToObject(date)->IsObject()); + EXPECT_TRUE(engine()->ToArray(date).IsEmpty()); +} + +TEST_F(FXJSV8EmbedderTest, NewArray) { + v8::Isolate::Scope isolate_scope(isolate()); + v8::HandleScope handle_scope(isolate()); + v8::Context::Scope context_scope(GetV8Context()); + + auto array = engine()->NewArray(); + EXPECT_EQ(0u, engine()->GetArrayLength(array)); + EXPECT_FALSE(engine()->GetArrayElement(array, 2).IsEmpty()); + EXPECT_TRUE(engine()->GetArrayElement(array, 2)->IsUndefined()); + EXPECT_EQ(0u, engine()->GetArrayLength(array)); + + engine()->PutArrayElement(array, 3, engine()->NewNumber(12)); + EXPECT_FALSE(engine()->GetArrayElement(array, 2).IsEmpty()); + EXPECT_TRUE(engine()->GetArrayElement(array, 2)->IsUndefined()); + EXPECT_FALSE(engine()->GetArrayElement(array, 3).IsEmpty()); + EXPECT_TRUE(engine()->GetArrayElement(array, 3)->IsNumber()); + EXPECT_EQ(4u, engine()->GetArrayLength(array)); + + EXPECT_TRUE(engine()->ToBoolean(array)); + EXPECT_EQ(0, engine()->ToInt32(array)); + double d = engine()->ToDouble(array); + EXPECT_NE(d, d); // i.e. NaN. + EXPECT_EQ(L",,,12", engine()->ToWideString(array)); + EXPECT_TRUE(engine()->ToObject(array)->IsObject()); + EXPECT_TRUE(engine()->ToArray(array)->IsArray()); +} + +TEST_F(FXJSV8EmbedderTest, NewObject) { + v8::Isolate::Scope isolate_scope(isolate()); + v8::HandleScope handle_scope(isolate()); + v8::Context::Scope context_scope(GetV8Context()); + + auto object = engine()->NewFxDynamicObj(-1); + EXPECT_EQ(0u, engine()->GetObjectPropertyNames(object).size()); + EXPECT_FALSE(engine()->GetObjectProperty(object, L"clams").IsEmpty()); + EXPECT_TRUE(engine()->GetObjectProperty(object, L"clams")->IsUndefined()); + EXPECT_EQ(0u, engine()->GetObjectPropertyNames(object).size()); + + engine()->PutObjectProperty(object, L"clams", engine()->NewNumber(12)); + EXPECT_FALSE(engine()->GetObjectProperty(object, L"clams").IsEmpty()); + EXPECT_TRUE(engine()->GetObjectProperty(object, L"clams")->IsNumber()); + EXPECT_EQ(1u, engine()->GetObjectPropertyNames(object).size()); + EXPECT_EQ(L"clams", engine()->GetObjectPropertyNames(object)[0]); + + EXPECT_TRUE(engine()->ToBoolean(object)); + EXPECT_EQ(0, engine()->ToInt32(object)); + double d = engine()->ToDouble(object); + EXPECT_NE(d, d); // i.e. NaN. + EXPECT_EQ(L"[object Object]", engine()->ToWideString(object)); + EXPECT_TRUE(engine()->ToObject(object)->IsObject()); + EXPECT_TRUE(engine()->ToArray(object).IsEmpty()); +} -- cgit v1.2.3