From 83d889098db7253a8d8bec7940a93724ea724449 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine
Date: Mon, 12 Sep 2011 17:21:07 +0300
Subject: STORM-1577 WIP Forgot to add the unit test.
---
indra/newview/tests/lltranslate_test.cpp | 344 +++++++++++++++++++++++++++++++
1 file changed, 344 insertions(+)
create mode 100644 indra/newview/tests/lltranslate_test.cpp
(limited to 'indra/newview/tests')
diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp
new file mode 100644
index 0000000000..0f3429b7b3
--- /dev/null
+++ b/indra/newview/tests/lltranslate_test.cpp
@@ -0,0 +1,344 @@
+/**
+ * @file lltranslate_test.cpp
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "../test/lltut.h"
+#include "../lltranslate.h"
+#include "../llversioninfo.h"
+#include "../llviewercontrol.h"
+
+#include "llbufferstream.h"
+#include "lltrans.h"
+#include "llui.h"
+
+static const std::string GOOGLE_VALID_RESPONSE1 =
+"{\
+ \"data\": {\
+ \"translations\": [\
+ {\
+ \"translatedText\": \"привет\",\
+ \"detectedSourceLanguage\": \"es\"\
+ }\
+ ]\
+ }\
+}";
+
+static const std::string GOOGLE_VALID_RESPONSE2 =
+"{\
+ \"data\": {\
+ \"translations\": [\
+ {\
+ \"translatedText\": \"привет\"\
+ }\
+ ]\
+ }\
+}\
+";
+
+static const std::string GOOGLE_VALID_RESPONSE3 =
+"{\
+ \"error\": {\
+ \"errors\": [\
+ {\
+ \"domain\": \"global\",\
+ \"reason\": \"invalid\",\
+ \"message\": \"Invalid Value\"\
+ }\
+ ],\
+ \"code\": 400,\
+ \"message\": \"Invalid Value\"\
+ }\
+}";
+
+static const std::string BING_VALID_RESPONSE1 =
+"Привет";
+
+static const std::string BING_VALID_RESPONSE2 =
+"Argument Exception
Method: Translate()
Parameter:
\
+Message: 'from' must be a valid language
\
+message id=3743.V2_Rest.Translate.58E8454F
";
+
+static const std::string BING_VALID_RESPONSE3 =
+"Argument Exception
Method: Translate()
\
+Parameter: appId
Message: Invalid appId
\nParameter name: appId
\
+message id=3737.V2_Rest.Translate.56016759
";
+
+namespace tut
+{
+ class translate_test
+ {
+ protected:
+ void test_translation(
+ LLTranslationAPIHandler& handler,
+ int status, const std::string& resp,
+ const std::string& exp_trans, const std::string& exp_lang, const std::string& exp_err)
+ {
+ std::string translation, detected_lang, err_msg;
+ bool rc = handler.parseResponse(status, resp, translation, detected_lang, err_msg);
+ ensure_equals("rc", rc, (status == 200));
+ ensure_equals("err_msg", err_msg, exp_err);
+ ensure_equals("translation", translation, exp_trans);
+ ensure_equals("detected_lang", detected_lang, exp_lang);
+ }
+
+ LLGoogleTranslationHandler mGoogle;
+ LLBingTranslarionHandler mBing;
+ };
+
+ typedef test_group translate_test_group_t;
+ typedef translate_test_group_t::object translate_test_object_t;
+ tut::translate_test_group_t tut_translate("LLTranslate");
+
+ template<> template<>
+ void translate_test_object_t::test<1>()
+ {
+ test_translation(mGoogle, 200, GOOGLE_VALID_RESPONSE1, "привет", "es", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<2>()
+ {
+ test_translation(mGoogle, 200, GOOGLE_VALID_RESPONSE2, "привет", "", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<3>()
+ {
+ test_translation(mGoogle, 400, GOOGLE_VALID_RESPONSE3, "", "", "Invalid Value");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<4>()
+ {
+ test_translation(mGoogle, 400,
+ "",
+ "", "", "* Line 1, Column 1\n Syntax error: value, object or array expected.\n");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<5>()
+ {
+ test_translation(mGoogle, 400,
+ "[]",
+ "", "", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<6>()
+ {
+ test_translation(mGoogle, 400,
+ "{\"oops\": \"invalid\"}",
+ "", "", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<7>()
+ {
+ test_translation(mGoogle, 400,
+ "{\"oops\": \"invalid\"}",
+ "", "", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<8>()
+ {
+ test_translation(mGoogle, 400,
+ "{\"data\": { \"translations\": [ {} ] }}",
+ "", "", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<9>()
+ {
+ test_translation(mGoogle, 400,
+ "{\"data\": { \"translations\": [ { \"translatedTextZZZ\": \"привет\", \"detectedSourceLanguageZZZ\": \"es\" } ] }}",
+ "", "", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<10>()
+ {
+ test_translation(mBing, 200, BING_VALID_RESPONSE1, "Привет", "", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<11>()
+ {
+ test_translation(mBing, 400, BING_VALID_RESPONSE2, "", "", "'from' must be a valid language");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<12>()
+ {
+ test_translation(mBing, 400, BING_VALID_RESPONSE3, "", "", "Invalid appId\nParameter name: appId");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<13>()
+ {
+ test_translation(mBing, 200,
+ "Привет",
+ "Привет", "", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<14>()
+ {
+ test_translation(mBing, 200,
+ "Привет",
+ "Привет", "", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<15>()
+ {
+ test_translation(mBing, 200,
+ "Привет",
+ "Привет", "", "");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<16>()
+ {
+ test_translation(mBing, 400,
+ "Message: some error
",
+ "", "", "some error");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<17>()
+ {
+ test_translation(mBing, 400,
+ "Message: some error",
+ "", "", "some error");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<18>()
+ {
+ test_translation(mBing, 400,
+ "some error",
+ "", "", "some error");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<19>()
+ {
+ test_translation(mBing, 400,
+ "some error",
+ "", "", "some error");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<20>()
+ {
+ std::string url;
+ mBing.getTranslateURL(url, "en", "es", "hi");
+ ensure_equals("bing URL", url,
+ "http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=dummy&text=hi&to=es&from=en");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<21>()
+ {
+ std::string url;
+ mBing.getTranslateURL(url, "", "es", "hi");
+ ensure_equals("bing URL", url,
+ "http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=dummy&text=hi&to=es");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<22>()
+ {
+ std::string url;
+ mGoogle.getTranslateURL(url, "en", "es", "hi");
+ ensure_equals("google URL", url,
+ "https://www.googleapis.com/language/translate/v2?key=dummy&q=hi&target=es&source=en");
+ }
+
+ template<> template<>
+ void translate_test_object_t::test<23>()
+ {
+ std::string url;
+ mGoogle.getTranslateURL(url, "", "es", "hi");
+ ensure_equals("google URL", url,
+ "https://www.googleapis.com/language/translate/v2?key=dummy&q=hi&target=es");
+ }
+}
+
+//== Misc stubs ===============================================================
+LLControlGroup gSavedSettings("test");
+
+std::string LLUI::getLanguage() { return "en"; }
+std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args) { return "dummy"; }
+
+LLControlGroup::LLControlGroup(const std::string& name) : LLInstanceTracker(name) {}
+std::string LLControlGroup::getString(const std::string& name) { return "dummy"; }
+LLControlGroup::~LLControlGroup() {}
+
+namespace boost {
+ void intrusive_ptr_add_ref(LLCurl::Responder*) {}
+ void intrusive_ptr_release(LLCurl::Responder*) {}
+}
+
+LLCurl::Responder::Responder() {}
+void LLCurl::Responder::completedHeader(U32, std::string const&, LLSD const&) {}
+void LLCurl::Responder::completedRaw(U32, const std::string&, const LLChannelDescriptors&, const LLIOPipe::buffer_ptr_t& buffer) {}
+void LLCurl::Responder::completed(U32, std::string const&, LLSD const&) {}
+void LLCurl::Responder::error(U32, std::string const&) {}
+void LLCurl::Responder::errorWithContent(U32, std::string const&, LLSD const&) {}
+void LLCurl::Responder::result(LLSD const&) {}
+LLCurl::Responder::~Responder() {}
+
+void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32) {}
+void LLHTTPClient::get(const std::string&, boost::intrusive_ptr, const LLSD&, const F32) {}
+
+LLBufferStream::LLBufferStream(const LLChannelDescriptors& channels, LLBufferArray* buffer) : mStreamBuf(channels, buffer) {}
+LLBufferStream::~LLBufferStream() {}
+
+LLBufferStreamBuf::LLBufferStreamBuf(const LLChannelDescriptors&, LLBufferArray*) {}
+#if( LL_WINDOWS || __GNUC__ > 2)
+LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff(
+ off_type off,
+ std::ios::seekdir way,
+ std::ios::openmode which)
+#else
+streampos LLBufferStreamBuf::seekoff(
+ streamoff off,
+ std::ios::seekdir way,
+ std::ios::openmode which)
+#endif
+{ return 0; }
+int LLBufferStreamBuf::sync() {return 0;}
+int LLBufferStreamBuf::underflow() {return 0;}
+int LLBufferStreamBuf::overflow(int) {return 0;}
+LLBufferStreamBuf::~LLBufferStreamBuf() {}
+
+S32 LLVersionInfo::getBuild() { return 0; }
+const std::string& LLVersionInfo::getChannel() {static std::string dummy; return dummy;}
+S32 LLVersionInfo::getMajor() { return 0; }
+S32 LLVersionInfo::getMinor() { return 0; }
+S32 LLVersionInfo::getPatch() { return 0; }
--
cgit v1.3
From 10b7c8d07f0c68613e29acecc334ea2d345d8ca3 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine
Date: Thu, 15 Sep 2011 14:55:32 +0300
Subject: STORM-1577 WIP Trying to fix a Windows compiler error in unit tests.
---
indra/newview/tests/lltranslate_test.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'indra/newview/tests')
diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp
index 0f3429b7b3..da11b8394a 100644
--- a/indra/newview/tests/lltranslate_test.cpp
+++ b/indra/newview/tests/lltranslate_test.cpp
@@ -316,7 +316,8 @@ LLCurl::Responder::~Responder() {}
void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32) {}
void LLHTTPClient::get(const std::string&, boost::intrusive_ptr, const LLSD&, const F32) {}
-LLBufferStream::LLBufferStream(const LLChannelDescriptors& channels, LLBufferArray* buffer) : mStreamBuf(channels, buffer) {}
+LLBufferStream::LLBufferStream(const LLChannelDescriptors& channels, LLBufferArray* buffer)
+: std::iostream(&mStreamBuf), mStreamBuf(channels, buffer) {}
LLBufferStream::~LLBufferStream() {}
LLBufferStreamBuf::LLBufferStreamBuf(const LLChannelDescriptors&, LLBufferArray*) {}
--
cgit v1.3
From 1474f8c9a288dbc475ae8c482ee9961a39e94c0a Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine
Date: Fri, 16 Sep 2011 00:38:17 +0300
Subject: STORM-1577 WIP Addressing review feedback.
* Don't enable the "Verify" button if use just moves cursor in the API key input field.
* Fixed copy&paste error in unit tests.
* Fixed a typo: LLBingTranslarionHandler
* Added Doxygen comments to lltranslate.h.
---
indra/newview/llfloatertranslationsettings.cpp | 12 ++-
indra/newview/lltranslate.cpp | 12 +--
indra/newview/lltranslate.h | 109 ++++++++++++++++++++++++-
indra/newview/tests/lltranslate_test.cpp | 4 +-
4 files changed, 123 insertions(+), 14 deletions(-)
(limited to 'indra/newview/tests')
diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp
index ac3e7ac8fa..ac4514b438 100644
--- a/indra/newview/llfloatertranslationsettings.cpp
+++ b/indra/newview/llfloatertranslationsettings.cpp
@@ -253,14 +253,18 @@ void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control)
void LLFloaterTranslationSettings::onBingKeyEdited()
{
- mBingAPIKeyEditor->setTentative(FALSE);
- setBingVerified(false, false);
+ if (mBingAPIKeyEditor->isDirty())
+ {
+ setBingVerified(false, false);
+ }
}
void LLFloaterTranslationSettings::onGoogleKeyEdited()
{
- mGoogleAPIKeyEditor->setTentative(FALSE);
- setGoogleVerified(false, false);
+ if (mGoogleAPIKeyEditor->isDirty())
+ {
+ setGoogleVerified(false, false);
+ }
}
void LLFloaterTranslationSettings::onBtnBingVerify()
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index 7b99c20a58..7eb54271f4 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -117,6 +117,8 @@ bool LLGoogleTranslationHandler::parseTranslation(
std::string& translation,
std::string& detected_lang)
{
+ // JsonCpp is prone to aborting the program on failed assertions,
+ // so be super-careful and verify the response format.
const Json::Value& data = root.get("data", 0);
if (!data.isObject() || !data.isMember("translations"))
{
@@ -147,7 +149,7 @@ std::string LLGoogleTranslationHandler::getAPIKey()
}
// virtual
-void LLBingTranslarionHandler::getTranslateURL(
+void LLBingTranslationHandler::getTranslateURL(
std::string &url,
const std::string &from_lang,
const std::string &to_lang,
@@ -162,7 +164,7 @@ void LLBingTranslarionHandler::getTranslateURL(
}
// virtual
-void LLBingTranslarionHandler::getKeyVerificationURL(
+void LLBingTranslationHandler::getKeyVerificationURL(
std::string& url,
const std::string& key) const
{
@@ -171,7 +173,7 @@ void LLBingTranslarionHandler::getKeyVerificationURL(
}
// virtual
-bool LLBingTranslarionHandler::parseResponse(
+bool LLBingTranslationHandler::parseResponse(
int& status,
const std::string& body,
std::string& translation,
@@ -217,7 +219,7 @@ bool LLBingTranslarionHandler::parseResponse(
}
// static
-std::string LLBingTranslarionHandler::getAPIKey()
+std::string LLBingTranslationHandler::getAPIKey()
{
return gSavedSettings.getString("BingTranslateAPIKey");
}
@@ -347,7 +349,7 @@ const LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
const LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
{
static LLGoogleTranslationHandler google;
- static LLBingTranslarionHandler bing;
+ static LLBingTranslationHandler bing;
if (service == SERVICE_GOOGLE)
{
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index 672a56af8b..c2330daa81 100644
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -35,19 +35,53 @@ namespace Json
class Value;
}
+/**
+ * Handler of an HTTP machine translation service.
+ *
+ * Derived classes know the service URL
+ * and how to parse the translation result.
+ */
class LLTranslationAPIHandler
{
public:
+ /**
+ * Get URL for translation of the given string.
+ *
+ * Sending HTTP GET request to the URL will initiate translation.
+ *
+ * @param[out] url Place holder for the result.
+ * @param from_lang Source language. Leave empty for auto-detection.
+ * @param to_lang Target language.
+ * @param text Text to translate.
+ */
virtual void getTranslateURL(
std::string &url,
const std::string &from_lang,
const std::string &to_lang,
const std::string &text) const = 0;
+ /**
+ * Get URL to verify the given API key.
+ *
+ * Sending request to the URL verifies the key.
+ * Positive HTTP response (code 200) means that the key is valid.
+ *
+ * @param[out] url Place holder for the URL.
+ * @param[in] key Key to verify.
+ */
virtual void getKeyVerificationURL(
std::string &url,
const std::string &key) const = 0;
+ /**
+ * Parse translation response.
+ *
+ * @param[in,out] status HTTP status. May be modified while parsing.
+ * @param body Response text.
+ * @param[out] translation Translated text.
+ * @param[out] detected_lang Detected source language. May be empty.
+ * @param[out] err_msg Error message (in case of error).
+ */
virtual bool parseResponse(
int& status,
const std::string& body,
@@ -61,6 +95,7 @@ protected:
static const int STATUS_OK = 200;
};
+/// Google Translate v2 API handler.
class LLGoogleTranslationHandler : public LLTranslationAPIHandler
{
LOG_CLASS(LLGoogleTranslationHandler);
@@ -93,9 +128,10 @@ private:
static std::string getAPIKey();
};
-class LLBingTranslarionHandler : public LLTranslationAPIHandler
+/// Microsoft Translator v2 API handler.
+class LLBingTranslationHandler : public LLTranslationAPIHandler
{
- LOG_CLASS(LLBingTranslarionHandler);
+ LOG_CLASS(LLBingTranslationHandler);
public:
/*virtual*/ void getTranslateURL(
@@ -116,7 +152,18 @@ private:
static std::string getAPIKey();
};
-
+/**
+ * Entry point for machine translation services.
+ *
+ * Basically, to translate a string, we need to know the URL
+ * of a translation service, have a valid API for the service
+ * and be given the target language.
+ *
+ * Callers specify the string to translate and the target language,
+ * LLTranslate takes care of the rest.
+ *
+ * API keys for translation are taken from saved settings.
+ */
class LLTranslate
{
LOG_CLASS(LLTranslate);
@@ -128,9 +175,23 @@ public :
SERVICE_GOOGLE,
} EService;
+ /**
+ * Subclasses are supposed to handle translation results (e.g. show them in chat)
+ */
class TranslationReceiver: public LLHTTPClient::Responder
{
public:
+
+ /**
+ * Using mHandler, parse incoming response.
+ *
+ * Calls either handleResponse() or handleFailure()
+ * depending on the HTTP status code and parsing success.
+ *
+ * @see handleResponse()
+ * @see handleFailure()
+ * @see mHandler
+ */
/*virtual*/ void completedRaw(
U32 http_status,
const std::string& reason,
@@ -140,9 +201,13 @@ public :
protected:
friend class LLTranslate;
+ /// Remember source and target languages for subclasses to be able to filter inappropriate results.
TranslationReceiver(const std::string& from_lang, const std::string& to_lang);
+ /// Override point to handle successful translation.
virtual void handleResponse(const std::string &translation, const std::string &recognized_lang) = 0;
+
+ /// Override point to handle unsuccessful translation.
virtual void handleFailure(int status, const std::string& err_msg) = 0;
std::string mFromLang;
@@ -150,18 +215,41 @@ public :
const LLTranslationAPIHandler& mHandler;
};
+ /**
+ * Subclasses are supposed to handle API key verification result.
+ */
class KeyVerificationReceiver: public LLHTTPClient::Responder
{
public:
EService getService() const;
protected:
+ /**
+ * Save the translation service the key belongs to.
+ *
+ * Subclasses need to know it.
+ *
+ * @see getService()
+ */
KeyVerificationReceiver(EService service);
+
+ /**
+ * Parse verification response.
+ *
+ * Calls setVerificationStatus() with the verification status,
+ * which is true if HTTP status code is 200.
+ *
+ * @see setVerificationStatus()
+ */
/*virtual*/ void completedRaw(
U32 http_status,
const std::string& reason,
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer);
+
+ /**
+ * Override point for subclasses to handle key verification status.
+ */
virtual void setVerificationStatus(bool ok) = 0;
EService mService;
@@ -170,7 +258,22 @@ public :
typedef boost::intrusive_ptr TranslationReceiverPtr;
typedef boost::intrusive_ptr KeyVerificationReceiverPtr;
+ /**
+ * Translate given text.
+ *
+ * @param receiver Object to pass translation result to.
+ * @param from_lang Source language. Leave empty for auto-detection.
+ * @param to_lang Target language.
+ * @param mesg Text to translate.
+ */
static void translateMessage(TranslationReceiverPtr &receiver, const std::string &from_lang, const std::string &to_lang, const std::string &mesg);
+
+ /**
+ * Verify given API key of a translation service.
+ *
+ * @param receiver Object to pass verification result to.
+ * @param key Key to verify.
+ */
static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key);
static std::string getTranslateLanguage();
diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp
index da11b8394a..10e37fae97 100644
--- a/indra/newview/tests/lltranslate_test.cpp
+++ b/indra/newview/tests/lltranslate_test.cpp
@@ -105,7 +105,7 @@ namespace tut
}
LLGoogleTranslationHandler mGoogle;
- LLBingTranslarionHandler mBing;
+ LLBingTranslationHandler mBing;
};
typedef test_group translate_test_group_t;
@@ -158,7 +158,7 @@ namespace tut
void translate_test_object_t::test<7>()
{
test_translation(mGoogle, 400,
- "{\"oops\": \"invalid\"}",
+ "{\"data\": {}}",
"", "", "");
}
--
cgit v1.3