Commit 1ecb9c55 authored by Akihiro Ota's avatar Akihiro Ota Committed by Commit Bot

ChromeVox: Language switching test infrastructure clean up.

This does two things:
1. Cleans up the language switching code to use consistent terms. Most
notably, it changes all instances of "inner-node switching" to
"sub-node switching".
2. Cleans up the language switching test infrastructure. A test
naming scheme was implemented to easily communicate the purpose of
each test. Also, tests were added to cover the two language switching
behaviors: node-level and sub-node-level switching. Each document
in the test databank is tested using node-level and sub-node-level
switching.

Bug: 923068
Change-Id: Ia16b785381966d97e089aae5dc08e23173876d08
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1754703
Commit-Queue: Akihiro Ota <akihiroota@chromium.org>
Reviewed-by: default avatarAlice Boxhall <aboxhall@chromium.org>
Reviewed-by: default avatarChris Hall <chrishall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690998}
parent e2dfd8ad
...@@ -5,29 +5,30 @@ ...@@ -5,29 +5,30 @@
/** /**
* @fileoverview Provides language switching services for ChromeVox, which * @fileoverview Provides language switching services for ChromeVox, which
* uses language detection information to automatically change the ChromeVox * uses language detection information to automatically change the ChromeVox
* output language. * output voice.
*/ */
goog.provide('LanguageSwitching'); goog.provide('LanguageSwitching');
/** /**
* The current output language. Initialize to the language of the browser or * The current output language. Initialize to the language of the browser or
* empty string if unavailable. * empty string if the former is unavailable.
* @private {string} * @private {string}
*/ */
LanguageSwitching.currentLanguage_ = LanguageSwitching.currentLanguage_ =
chrome.i18n.getUILanguage().toLowerCase() || ''; chrome.i18n.getUILanguage().toLowerCase() || '';
/** /**
* Confidence threshold to meet before assigning inner-node language. * Confidence threshold to meet before assigning sub-node language.
* @const * @const
* @private {number} * @private {number}
*/ */
LanguageSwitching.PROBABILITY_THRESHOLD = 0.9; LanguageSwitching.PROBABILITY_THRESHOLD_ = 0.9;
/** /**
* Stores whether or not ChromeVox inner-node language switching is enabled or * Stores whether or not ChromeVox sub-node language switching is enabled.
* disabled. * Set to false as default, as sub-node language detection is still
* experimental.
* @private {boolean} * @private {boolean}
*/ */
LanguageSwitching.sub_node_switching_enabled_ = false; LanguageSwitching.sub_node_switching_enabled_ = false;
...@@ -36,8 +37,7 @@ LanguageSwitching.sub_node_switching_enabled_ = false; ...@@ -36,8 +37,7 @@ LanguageSwitching.sub_node_switching_enabled_ = false;
* Initialization function for language switching. * Initialization function for language switching.
*/ */
LanguageSwitching.init = function() { LanguageSwitching.init = function() {
// Enable inner-node language switching if inner-node switching feature flag // Enable sub-node language switching if feature flag is enabled.
// is enabled.
chrome.commandLinePrivate.hasSwitch( chrome.commandLinePrivate.hasSwitch(
'enable-experimental-accessibility-chromevox-sub-node-language-' + 'enable-experimental-accessibility-chromevox-sub-node-language-' +
'switching', 'switching',
...@@ -64,7 +64,6 @@ LanguageSwitching.assignLanguagesForStringAttribute = function( ...@@ -64,7 +64,6 @@ LanguageSwitching.assignLanguagesForStringAttribute = function(
return; return;
var stringAttributeValue = node[stringAttribute]; var stringAttributeValue = node[stringAttribute];
var languageAnnotation; var languageAnnotation;
// Quick note: // Quick note:
// The decideNewLanguage function, which contains the core language switching // The decideNewLanguage function, which contains the core language switching
// logic, is setup to prefer sub-node switching if the detected language's // logic, is setup to prefer sub-node switching if the detected language's
...@@ -74,18 +73,10 @@ LanguageSwitching.assignLanguagesForStringAttribute = function( ...@@ -74,18 +73,10 @@ LanguageSwitching.assignLanguagesForStringAttribute = function(
languageAnnotation = languageAnnotation =
node.languageAnnotationForStringAttribute(stringAttribute); node.languageAnnotationForStringAttribute(stringAttribute);
} else { } else {
// Use node-level language switching if inner-node switching is
// disabled. We use this logic because the API is disabled when sub-node
// switching is disabled.
var nodeLevelLanguageData = {}; var nodeLevelLanguageData = {};
// Ensure that we span the entire stringAttributeValue. // Ensure that we span the entire stringAttributeValue.
nodeLevelLanguageData.startIndex = 0; nodeLevelLanguageData.startIndex = 0;
nodeLevelLanguageData.endIndex = stringAttributeValue.length; nodeLevelLanguageData.endIndex = stringAttributeValue.length;
// To force the decideNewLanguage function to use node-level switching, we
// pass in an empty language with probability that doesn't exceed the
// PROBABILITY_THRESHOLD. As previously mentioned, if we are not confident
// enough in inner-node detected languages, we fall back on node-level
// language.
nodeLevelLanguageData.language = ''; nodeLevelLanguageData.language = '';
nodeLevelLanguageData.probability = 0; nodeLevelLanguageData.probability = 0;
languageAnnotation = [nodeLevelLanguageData]; languageAnnotation = [nodeLevelLanguageData];
...@@ -100,9 +91,10 @@ LanguageSwitching.assignLanguagesForStringAttribute = function( ...@@ -100,9 +91,10 @@ LanguageSwitching.assignLanguagesForStringAttribute = function(
stringAttributeValue || '', LanguageSwitching.currentLanguage_); stringAttributeValue || '', LanguageSwitching.currentLanguage_);
return; return;
} }
// Split output based on language annotation. // Split output based on language annotation.
// Each object in languageAnnotation contains a language, probability, // Each object in languageAnnotation contains a language, probability,
// and start/end indices that define a substring. // and start/end indices that define a substring of stringAttributeValue.
for (var i = 0; i < languageAnnotation.length; ++i) { for (var i = 0; i < languageAnnotation.length; ++i) {
var speechProps = new Output.SpeechProperties(); var speechProps = new Output.SpeechProperties();
var startIndex = languageAnnotation[i].startIndex; var startIndex = languageAnnotation[i].startIndex;
...@@ -130,14 +122,14 @@ LanguageSwitching.assignLanguagesForStringAttribute = function( ...@@ -130,14 +122,14 @@ LanguageSwitching.assignLanguagesForStringAttribute = function(
/** /**
* Run error checks on language data and decide new output language. * Run error checks on language data and decide new output language.
* @param {!AutomationNode} node * @param {!AutomationNode} node
* @param {string} innerNodeLanguage * @param {string} subNodeLanguage
* @param {number} probability * @param {number} probability
* @return {string} * @return {string}
*/ */
LanguageSwitching.decideNewLanguage = function( LanguageSwitching.decideNewLanguage = function(
node, innerNodeLanguage, probability) { node, subNodeLanguage, probability) {
// Use the following priority rankings when deciding language. // Use the following priority rankings when deciding language.
// 1. Inner-node language. If we can detect inner-node language with a high // 1. Sub-node language. If we can detect sub-node language with a high
// enough probability of accuracy, then we should use it. // enough probability of accuracy, then we should use it.
// 2. Node-level detected language. // 2. Node-level detected language.
// 3. Author-provided language. This language is also assigned at the node // 3. Author-provided language. This language is also assigned at the node
...@@ -145,9 +137,9 @@ LanguageSwitching.decideNewLanguage = function( ...@@ -145,9 +137,9 @@ LanguageSwitching.decideNewLanguage = function(
// 4. LanguageSwitching.currentLanguage_. If we do not have enough language // 4. LanguageSwitching.currentLanguage_. If we do not have enough language
// data, then we should not switch languages. // data, then we should not switch languages.
// Use innerNodeLanguage if probability exceeds threshold. // Use subNodeLanguage if probability exceeds threshold.
if (probability > LanguageSwitching.PROBABILITY_THRESHOLD) if (probability > LanguageSwitching.PROBABILITY_THRESHOLD_)
return innerNodeLanguage.toLowerCase(); return subNodeLanguage.toLowerCase();
// Use detected language as nodeLevelLanguage, if present. // Use detected language as nodeLevelLanguage, if present.
// If no detected language, use author-provided language. // If no detected language, use author-provided language.
...@@ -181,7 +173,7 @@ LanguageSwitching.decideNewLanguage = function( ...@@ -181,7 +173,7 @@ LanguageSwitching.decideNewLanguage = function(
}; };
/** /**
* Returns a unicode-aware substring of text from startIndex to endIndex. * Returns a unicode-aware substring of |text| from startIndex to endIndex.
* @param {string} text * @param {string} text
* @param {number} startIndex * @param {number} startIndex
* @param {number} endIndex * @param {number} endIndex
......
...@@ -83,82 +83,96 @@ ChromeVoxLanguageSwitchingTest.prototype = { ...@@ -83,82 +83,96 @@ ChromeVoxLanguageSwitchingTest.prototype = {
} }
}, },
multipleLanguagesDoc: function() {/*!
<p lang="es">Hola.</p>
<p lang="en">Hello.</p>
<p lang="fr">Salut.</p>
<span lang="it">Ciao amico.</span>
*/},
nestedLanguagesDoc: function() {/*! // Test documents //
<p id="breakfast" lang="en">In the morning, I sometimes eat breakfast.</p>
<p id="lunch" lang="fr">Dans l'apres-midi, je dejeune.</p>
<p id="greeting" lang="en"> // The purpose of this doc is to test functionality with three-letter language
Hello it's a pleasure to meet you. // codes. Asturian has a language code of 'ast'. It is a language spoken
<span lang="fr">Comment ca va?</span>Switching back to English. // in Principality of Asturias, Spain.
<span lang="es">Hola.</span>Goodbye. asturianAndJapaneseDoc: function() {/*!
<meta charset="utf-8">
<p lang="ja">ど</p>
<p lang="ast">
Pretend that this text is Asturian. Testing three-letter language code logic.
</p> </p>
*/}, */},
buttonAndLinkDoc: function() {/*! buttonAndLinkDoc: function() {/*!
<body lang="es"> <body lang="es">
<p>This is a paragraph, spoken in English.</p> <p>This is a paragraph, written in English.</p>
<button type="submit">This is a button, spoken in English.</button> <button type="submit">This is a button, written in English.</button>
<a href="https://www.google.com">Este es un enlace.</a> <a href="https://www.google.com">Este es un enlace.</a>
</body> </body>
*/}, */},
japaneseAndEnglishDoc: function() {/*! englishAndFrenchUnlabeledDoc: function() {/*!
<meta charset="utf-8">
<p>Hello, my name is 太田あきひろ. It's a pleasure to meet you. どうぞよろしくお願いします.</p>
*/},
switchWhenUnlabeledDoc: function() {/*!
<meta charset="utf-8">
<p>This text should be read in English. 차에 한하여 중임할 수. Followed by English.</p>
*/},
noSwitchEnglishFrenchDoc: function() {/*!
<p> <p>
This entire object should be read in English, even the following French passage: This entire object should be read in English, even the following French passage:
salut mon ami! Ca va? Bien, et toi? It's hard to differentiate between latin-based languages. salut mon ami! Ca va? Bien, et toi? It's hard to differentiate between latin-based languages.
</p> </p>
*/}, */},
englishAndKoreanUnlabeledDoc: function() {/*!
<meta charset="utf-8">
<p>This text is written in English. 차에 한하여 중임할 수. This text is also written in English.</p>
*/},
japaneseAndChineseUnlabeledDoc: function() {/*! japaneseAndChineseUnlabeledDoc: function() {/*!
<meta charset="utf-8"> <meta charset="utf-8">
<p> <p id="text">
天気はいいですね. 右万諭全中結社原済権人点掲年難出面者会追 天気はいいですね. 右万諭全中結社原済権人点掲年難出面者会追
</p> </p>
*/}, */},
japaneseAndKoreanNotEnoughJapaneseDoc: function() {/*! japaneseAndEnglishUnlabeledDoc: function() {/*!
<meta charset="utf-8">
<p>Hello, my name is 太田あきひろ. It's a pleasure to meet you. どうぞよろしくお願いします.</p>
*/},
japaneseAndKoreanUnlabeledDoc: function() {/*!
<meta charset="utf-8"> <meta charset="utf-8">
<p lang="ko"> <p lang="ko">
私は. 법률이 정하는 바에 의하여 대법관이 아닌 법관을 둘 수 있다 私は. 법률이 정하는 바에 의하여 대법관이 아닌 법관을 둘 수 있다
</p> </p>
*/}, */},
unlabeledSingleCharacterDoc: function() {/*! japaneseCharacterUnlabeledDoc: function() {/*!
<meta charset="utf-8"> <meta charset="utf-8">
<p>ど</p> <p>ど</p>
*/}, */},
// The purpose of this doc is to test functionality with three-letter language multipleLanguagesLabeledDoc: function() {/*!
// codes. Asturian has a language code of 'ast'. It is a language spoken <p lang="es">Hola.</p>
// in Principality of Asturias, Spain. <p lang="en">Hello.</p>
asturianAndJapaneseDoc: function() {/*! <p lang="fr">Salut.</p>
<meta charset="utf-8"> <span lang="it">Ciao amico.</span>
<p lang="ja">ど</p> */},
<p lang="ast">
Pretend that this text is Asturian. Testing three-letter language code logic. nestedLanguagesLabeledDoc: function() {/*!
<p id="breakfast" lang="en">In the morning, I sometimes eat breakfast.</p>
<p id="lunch" lang="fr">Dans l'apres-midi, je dejeune.</p>
<p id="greeting" lang="en">
Hello it's a pleasure to meet you.
<span lang="fr">Comment ca va?</span>Switching back to English.
<span lang="es">Hola.</span>Goodbye.
</p> </p>
*/}, */},
}; };
TEST_F('ChromeVoxLanguageSwitchingTest', 'MultipleLanguagesTest', function() { // Overview:
// The naming scheme of the language switching tests is as follows:
// <switching_behavior>_<test_document>_Test.
// <switching_behavior>: Whether the test is testing node-level or sub-node-level switching.
// <test_document>: The name of the document the test uses.
// Example: NodeLevelSwitching_MultipleLanguagesLabeledDoc_Test
// Each group of tests test the two switching behaviors with various labelings.
TEST_F('ChromeVoxLanguageSwitchingTest', 'SubNodeLevelSwitching_MultipleLanguagesLabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.multipleLanguagesDoc, function() { this.runWithLoadedTree(this.multipleLanguagesLabeledDoc, function() {
// Turn on language switching. // Turn on language switching.
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
mockFeedback.call(doCmd('jumpToTop')).expectSpeechWithLanguage('es', 'español: Hola.'); mockFeedback.call(doCmd('jumpToTop')).expectSpeechWithLanguage('es', 'español: Hola.');
...@@ -169,9 +183,26 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'MultipleLanguagesTest', function() { ...@@ -169,9 +183,26 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'MultipleLanguagesTest', function() {
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'NestedLanguagesTest', function() { TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_MultipleLanguagesLabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.nestedLanguagesDoc, function() { this.runWithLoadedTree(this.multipleLanguagesLabeledDoc, function() {
localStorage['languageSwitching'] = 'true';
// Disable sub-node-level switching.
LanguageSwitching.sub_node_switching_enabled_ = false;
mockFeedback.call(doCmd('jumpToTop')).expectSpeechWithLanguage('es', 'español: Hola.');
mockFeedback.call(doCmd('nextLine')).expectSpeechWithLanguage('en', 'English: Hello.');
mockFeedback.call(doCmd('nextLine')).expectSpeechWithLanguage('fr', 'français: Salut.');
mockFeedback.call(doCmd('nextLine')).expectSpeechWithLanguage('it', 'italiano: Ciao amico.');
mockFeedback.replay();
});
});
TEST_F('ChromeVoxLanguageSwitchingTest', 'SubNodeLevelSwitching_NestedLanguagesLabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.nestedLanguagesLabeledDoc, function() {
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
// We should be able to switch languages when each component is labeled // We should be able to switch languages when each component is labeled
// with a language. // with a language.
...@@ -195,20 +226,45 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'NestedLanguagesTest', function() { ...@@ -195,20 +226,45 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'NestedLanguagesTest', function() {
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'ButtonAndLinkTest', function() { TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_NestedLanguagesLabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.nestedLanguagesLabeledDoc, function() {
localStorage['languageSwitching'] = 'true';
// Disable sub-node-switching.
LanguageSwitching.sub_node_switching_enabled_ = false;
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLanguage('en', 'In the morning, I sometimes eat breakfast.');
mockFeedback.call(doCmd('nextLine'))
.expectSpeechWithLanguage('fr', "français: Dans l'apres-midi, je dejeune.");
mockFeedback.call(doCmd('nextLine'))
.expectSpeechWithLanguage('en', "English: Hello it's a pleasure to meet you. ");
mockFeedback.call(doCmd('nextLine'))
.expectSpeechWithLanguage('fr', 'français: Comment ca va?');
mockFeedback.call(doCmd('nextLine'))
.expectSpeechWithLanguage('en', 'English: Switching back to English. ');
mockFeedback.call(doCmd('nextLine'))
.expectSpeechWithLanguage('es', 'español: Hola.');
mockFeedback.call(doCmd('nextLine'))
.expectSpeechWithLanguage('en', 'English: Goodbye.');
mockFeedback.replay();
});
});
TEST_F('ChromeVoxLanguageSwitchingTest', 'SubNodeLevelSwitching_ButtonAndLinkDoc_Test', function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.buttonAndLinkDoc, function(root) { this.runWithLoadedTree(this.buttonAndLinkDoc, function(root) {
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
// Inner-node language detection is able to label this as 'en' and // Sub-node language detection is able to label this as 'en' and
// overwrite the author-provided language of 'es'. // overwrite the author-provided language of 'es'.
// LanguageSwitching.currentLanguage_ is initialized to 'en'. Do not // LanguageSwitching.currentLanguage_ is initialized to 'en'. Do not
// prepend 'English' because language does not switch. // prepend 'English' because language does not switch.
.expectSpeechWithLanguage('en', 'This is a paragraph, spoken in English.') .expectSpeechWithLanguage('en', 'This is a paragraph, written in English.')
.call(doCmd('nextObject')) .call(doCmd('nextObject'))
// Even though this is unlabeled, CLD3 is able to determine, with high // CLD3 is able to determine, with high confidence, that this is English text.
// confidence, that this is English text. .expectSpeechWithLanguage('en', 'This is a button, written in English.')
.expectSpeechWithLanguage('en', 'This is a button, spoken in English.')
.expectSpeechWithLanguage(undefined, 'Button', 'Press Search+Space to activate.') .expectSpeechWithLanguage(undefined, 'Button', 'Press Search+Space to activate.')
.call(doCmd('nextObject')) .call(doCmd('nextObject'))
.expectSpeechWithLanguage('es', 'español: Este es un enlace.') .expectSpeechWithLanguage('es', 'español: Este es un enlace.')
...@@ -217,9 +273,31 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'ButtonAndLinkTest', function() { ...@@ -217,9 +273,31 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'ButtonAndLinkTest', function() {
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndEnglishUnlabeledTest', function() { TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_ButtonAndLinkDoc_Test', function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.japaneseAndEnglishDoc, function(root) { this.runWithLoadedTree(this.buttonAndLinkDoc, function(root) {
localStorage['languageSwitching'] = 'true';
// Disable sub-node-switching.
LanguageSwitching.sub_node_switching_enabled_ = false;
mockFeedback.call(doCmd('jumpToTop'))
// Sub-node language detection is disabled, so we are not able to detect + switch to English
// on any of these nodes. Instead, we use the author-provided language of 'es'.
.expectSpeechWithLanguage('es', 'español: This is a paragraph, written in English.')
.call(doCmd('nextObject'))
.expectSpeechWithLanguage('es', 'This is a button, written in English.')
.expectSpeechWithLanguage(undefined, 'Button', 'Press Search+Space to activate.')
.call(doCmd('nextObject'))
.expectSpeechWithLanguage('es', 'Este es un enlace.')
.expectSpeechWithLanguage(undefined, 'Link');
mockFeedback.replay();
});
});
TEST_F('ChromeVoxLanguageSwitchingTest','SubNodeLevelSwitching_JapaneseAndEnglishUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.japaneseAndEnglishUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
// We are able to separate out English and Japanese because they use // We are able to separate out English and Japanese because they use
// different scripts. // different scripts.
...@@ -228,7 +306,7 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndEnglishUnlabeledTest', func ...@@ -228,7 +306,7 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndEnglishUnlabeledTest', func
// prepend 'English' because language does not switch. // prepend 'English' because language does not switch.
.expectSpeechWithLanguage('en', 'Hello, my name is ') .expectSpeechWithLanguage('en', 'Hello, my name is ')
.expectSpeechWithLanguage('ja', '日本語: 太田あきひろ. ') .expectSpeechWithLanguage('ja', '日本語: 太田あきひろ. ')
// Expect 'en-us' because inner-node language of 'en' doesn't come with // Expect 'en-us' because sub-node language of 'en' doesn't come with
// high enough probability. We fall back on node-level detected language, // high enough probability. We fall back on node-level detected language,
// which is 'en-us'. // which is 'en-us'.
.expectSpeechWithLanguage('en-us', "English: It's a pleasure to meet you. ") .expectSpeechWithLanguage('en-us', "English: It's a pleasure to meet you. ")
...@@ -237,10 +315,10 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndEnglishUnlabeledTest', func ...@@ -237,10 +315,10 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndEnglishUnlabeledTest', func
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndEnglishUnlabeledTestSubNodeSwitchingDisabled', TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_JapaneseAndEnglishUnlabeledDoc_Test',
function() { function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.japaneseAndEnglishDoc, function(root) { this.runWithLoadedTree(this.japaneseAndEnglishUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
// Disable sub-node-switching. // Disable sub-node-switching.
LanguageSwitching.sub_node_switching_enabled_ = false; LanguageSwitching.sub_node_switching_enabled_ = false;
...@@ -255,28 +333,46 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndEnglishUnlabeledTestSubNode ...@@ -255,28 +333,46 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndEnglishUnlabeledTestSubNode
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'SwitchWhenUnlabeledTest', function() {
TEST_F('ChromeVoxLanguageSwitchingTest', 'SubNodeLevelSwitching_EnglishAndKoreanUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.switchWhenUnlabeledDoc, function(root) { this.runWithLoadedTree(this.englishAndKoreanUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
// We are able to separate out English and Korean because they use // We are able to separate out English and Korean because they use
// different scripts. // different scripts.
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
// LanguageSwitching.currentLanguage_ is initialized to 'en'. Do not // LanguageSwitching.currentLanguage_ is initialized to 'en'. Do not
// prepend 'English' because language does not switch. // prepend 'English' because language does not switch.
.expectSpeechWithLanguage('en', 'This text should be read in English. ') .expectSpeechWithLanguage('en', 'This text is written in English. ')
.expectSpeechWithLanguage('ko', '한국어: 차에 한하여 중임할 수. ') .expectSpeechWithLanguage('ko', '한국어: 차에 한하여 중임할 수. ')
// Expect 'en-us' because inner-node language of 'en' doesn't come with // Expect 'en-us' because sub-node language of 'en' doesn't come with
// high enough probability. We fall back on node-level detected language, // high enough probability. We fall back on node-level detected language,
// which is 'en-us'. // which is 'en-us'.
.expectSpeechWithLanguage('en-us', 'English: Followed by English.'); .expectSpeechWithLanguage('en', 'English: This text is also written in English.');
mockFeedback.replay();
});
});
TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_EnglishAndKoreanUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.englishAndKoreanUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true';
// Disable sub-node-switching
LanguageSwitching.sub_node_switching_enabled_ = false;
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLanguage('en-us', 'This text is written in English. 차에 한하여 중임할 수.'
+ ' This text is also written in English.');
mockFeedback.replay(); mockFeedback.replay();
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'NoSwitchEnglishFrenchTest', function() {
TEST_F('ChromeVoxLanguageSwitchingTest', 'SubNodeLevelSwitching_EnglishAndFrenchUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.noSwitchEnglishFrenchDoc, function(root) { this.runWithLoadedTree(this.englishAndFrenchUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
// Unable to separate out English and French when unlabeled. // Unable to separate out English and French when unlabeled.
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
...@@ -289,9 +385,25 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'NoSwitchEnglishFrenchTest', function() ...@@ -289,9 +385,25 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'NoSwitchEnglishFrenchTest', function()
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'UnlabeledSingleCharacterTest', function() { TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_EnglishAndFrenchUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.unlabeledSingleCharacterDoc, function(root) { this.runWithLoadedTree(this.englishAndFrenchUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true';
LanguageSwitching.sub_node_switching_enabled_ = false;
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLanguage('en', 'This entire object should be read in English, even'
+ ' the following French passage: salut mon ami! Ca va? Bien, et toi? It\'s hard to'
+ ' differentiate between latin-based languages.');
mockFeedback.replay();
});
});
TEST_F('ChromeVoxLanguageSwitchingTest', 'SubNodeLevelSwitching_JapaneseCharacterUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.japaneseCharacterUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
// We are able to detect and switch at the character level if the character // We are able to detect and switch at the character level if the character
// is unique to a certian script. In this case, 'ど' only appears in // is unique to a certian script. In this case, 'ど' only appears in
...@@ -302,7 +414,21 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'UnlabeledSingleCharacterTest', functio ...@@ -302,7 +414,21 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'UnlabeledSingleCharacterTest', functio
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndChineseUnlabeled', function() { TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_JapaneseCharacterUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.japaneseCharacterUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true';
LanguageSwitching.sub_node_switching_enabled_ = false;
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLanguage('en-us', 'ど');
mockFeedback.replay();
});
});
TEST_F('ChromeVoxLanguageSwitchingTest','SubNodeLevelSwitching_JapaneseAndChineseUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.japaneseAndChineseUnlabeledDoc, function(root) { this.runWithLoadedTree(this.japaneseAndChineseUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
...@@ -314,9 +440,44 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndChineseUnlabeled', function ...@@ -314,9 +440,44 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndChineseUnlabeled', function
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndKoreanNotEnoughJapanese', function() { TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_JapaneseAndChineseUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.japaneseAndChineseUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true';
LanguageSwitching.sub_node_switching_enabled_ = false;
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLanguage('en-us', '天気はいいですね. 右万諭全中結社原済権人点掲年難出面者会追');
mockFeedback.replay();
});
});
TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_JapaneseAndChineseLabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback();
// Only difference between doc used in this test and this.japaneseAndChineseUnlabeledDoc is the
// lang="zh" attribute.
this.runWithLoadedTree(
function() {/*!
<meta charset="utf-8">
<p lang="zh">
天気はいいですね. 右万諭全中結社原済権人点掲年難出面者会追
</p>
*/},
function(root) {
localStorage['languageSwitching'] = 'true';
LanguageSwitching.sub_node_switching_enabled_ = false;
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLanguage('zh', '中文: 天気はいいですね. 右万諭全中結社原済権人点掲年難出面者会追');
mockFeedback.replay();
});
});
TEST_F('ChromeVoxLanguageSwitchingTest', 'SubNodeLevelSwitching_JapaneseAndKoreanUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.japaneseAndKoreanNotEnoughJapaneseDoc, function(root) { this.runWithLoadedTree(this.japaneseAndKoreanUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
// Unable to separate out Japanese and Korean if unlabeled. // Unable to separate out Japanese and Korean if unlabeled.
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
...@@ -326,7 +487,23 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndKoreanNotEnoughJapanese', f ...@@ -326,7 +487,23 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'JapaneseAndKoreanNotEnoughJapanese', f
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'AsturianTest', function() { TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_JapaneseAndKoreanUnlabeledDoc_Test',
function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.japaneseAndKoreanUnlabeledDoc, function(root) {
localStorage['languageSwitching'] = 'true';
LanguageSwitching.sub_node_switching_enabled_ = false;
// Node-level language detection runs and assigns language of 'ko' to the node.
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLanguage('ko', '한국어: 私は. 법률이 정하는 바에 의하여 대법관이 아닌 법관을 둘 수'
+ ' 있다');
mockFeedback.replay();
});
});
TEST_F('ChromeVoxLanguageSwitchingTest', 'SubNodeLevelSwitching_AsturianAndJapaneseDoc_Test',
function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.asturianAndJapaneseDoc, function(root) { this.runWithLoadedTree(this.asturianAndJapaneseDoc, function(root) {
localStorage['languageSwitching'] = 'true'; localStorage['languageSwitching'] = 'true';
...@@ -339,9 +516,26 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'AsturianTest', function() { ...@@ -339,9 +516,26 @@ TEST_F('ChromeVoxLanguageSwitchingTest', 'AsturianTest', function() {
}); });
}); });
TEST_F('ChromeVoxLanguageSwitchingTest', 'NodeLevelSwitching_AsturianAndJapaneseDoc_Test',
function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.asturianAndJapaneseDoc, function(root) {
localStorage['languageSwitching'] = 'true';
LanguageSwitching.sub_node_level_switching_enabled_ = false;
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLanguage('ja', '日本語: ど')
.call(doCmd('nextObject'))
.expectSpeechWithLanguage('ast', 'asturianu: Pretend that this text is Asturian. Testing'
+ ' three-letter language code logic.');
mockFeedback.replay();
});
});
// This does not need partner tests because no language switching behavior is tested.
TEST_F('ChromeVoxLanguageSwitchingTest', 'LanguageSwitchingOffTest', function() { TEST_F('ChromeVoxLanguageSwitchingTest', 'LanguageSwitchingOffTest', function() {
var mockFeedback = this.createMockFeedback(); var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.multipleLanguagesDoc, function(root) { this.runWithLoadedTree(this.multipleLanguagesLabeledDoc, function(root) {
localStorage['languageSwitching'] = 'false'; localStorage['languageSwitching'] = 'false';
// Language should not be set if the language switching feature is off. // Language should not be set if the language switching feature is off.
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment