blob: 0c6c7db69b7bcefab0958ad018ff9bea6c1b887a [file] [log] [blame]
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "cobalt/accessibility/internal/text_alternative_helper.h"
#include "cobalt/dom/html_image_element.h"
#include "cobalt/dom/text.h"
#include "cobalt/test/empty_document.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cobalt {
namespace accessibility {
namespace internal {
class TextAlternativeHelperTest : public ::testing::Test {
protected:
dom::Document* document() { return empty_document_.document(); }
TextAlternativeHelper text_alternative_helper_;
test::EmptyDocument empty_document_;
};
TEST_F(TextAlternativeHelperTest, ConcatenatesAlternatives) {
EXPECT_TRUE(text_alternative_helper_.AppendTextIfNonEmpty("test"));
EXPECT_TRUE(text_alternative_helper_.AppendTextIfNonEmpty("dog"));
EXPECT_TRUE(text_alternative_helper_.AppendTextIfNonEmpty("cat"));
EXPECT_STREQ("test dog cat",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, IgnoresEmptyStrings) {
EXPECT_FALSE(text_alternative_helper_.AppendTextIfNonEmpty(""));
EXPECT_STREQ("", text_alternative_helper_.GetTextAlternative().c_str());
EXPECT_FALSE(text_alternative_helper_.AppendTextIfNonEmpty(" "));
EXPECT_TRUE(text_alternative_helper_.GetTextAlternative().empty());
}
TEST_F(TextAlternativeHelperTest, TrimsAlternatives) {
EXPECT_TRUE(text_alternative_helper_.AppendTextIfNonEmpty(" test "));
EXPECT_TRUE(text_alternative_helper_.AppendTextIfNonEmpty("dog "));
EXPECT_TRUE(text_alternative_helper_.AppendTextIfNonEmpty(" cat"));
EXPECT_STREQ("test dog cat",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, HiddenOnlyIfAriaHiddenSet) {
scoped_refptr<dom::Element> element = document()->CreateElement("div");
// No aria-hidden attribute set.
EXPECT_FALSE(TextAlternativeHelper::IsAriaHidden(element));
// aria-hidden attribute set to false.
element->SetAttribute(base::Tokens::aria_hidden().c_str(),
base::Tokens::false_token().c_str());
EXPECT_FALSE(TextAlternativeHelper::IsAriaHidden(element));
// aria-hidden attribute set to true.
element->SetAttribute(base::Tokens::aria_hidden().c_str(),
base::Tokens::true_token().c_str());
EXPECT_TRUE(TextAlternativeHelper::IsAriaHidden(element));
// aria-hidden set to some arbitrary value.
element->SetAttribute(base::Tokens::aria_hidden().c_str(), "banana");
EXPECT_FALSE(TextAlternativeHelper::IsAriaHidden(element));
}
TEST_F(TextAlternativeHelperTest, GetTextAlternativeFromTextNode) {
scoped_refptr<dom::Element> element = document()->CreateElement("div");
element->AppendChild(document()->CreateTextNode("text node contents"));
text_alternative_helper_.AppendTextAlternative(element);
EXPECT_STREQ("text node contents",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, GetAltAttributeFromHTMLImage) {
scoped_refptr<dom::Element> element =
document()->CreateElement(dom::HTMLImageElement::kTagName);
element->SetAttribute(base::Tokens::alt().c_str(), "image alt text");
EXPECT_TRUE(text_alternative_helper_.TryAppendFromAltProperty(element));
EXPECT_STREQ("image alt text",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, EmptyAltAttribute) {
scoped_refptr<dom::Element> element =
document()->CreateElement(dom::HTMLImageElement::kTagName);
// No alt attribute.
EXPECT_FALSE(text_alternative_helper_.TryAppendFromAltProperty(element));
EXPECT_TRUE(text_alternative_helper_.GetTextAlternative().empty());
// Empty alt attribute.
element->SetAttribute(base::Tokens::alt().c_str(), "");
EXPECT_FALSE(text_alternative_helper_.TryAppendFromAltProperty(element));
EXPECT_TRUE(text_alternative_helper_.GetTextAlternative().empty());
}
TEST_F(TextAlternativeHelperTest, AltAttributeOnArbitraryElement) {
scoped_refptr<dom::Element> element = document()->CreateElement("div");
element->SetAttribute(base::Tokens::alt().c_str(), "alt text");
EXPECT_FALSE(text_alternative_helper_.TryAppendFromAltProperty(element));
EXPECT_TRUE(text_alternative_helper_.GetTextAlternative().empty());
}
TEST_F(TextAlternativeHelperTest, GetTextFromAriaLabel) {
scoped_refptr<dom::Element> element = document()->CreateElement("div");
element->SetAttribute(base::Tokens::aria_label().c_str(), "label text");
EXPECT_TRUE(text_alternative_helper_.TryAppendFromLabel(element));
EXPECT_STREQ("label text",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, IgnoreEmptyAriaLabel) {
scoped_refptr<dom::Element> element = document()->CreateElement("test");
element->SetAttribute(base::Tokens::aria_label().c_str(), " ");
EXPECT_FALSE(text_alternative_helper_.TryAppendFromLabel(element));
EXPECT_TRUE(text_alternative_helper_.GetTextAlternative().empty());
}
TEST_F(TextAlternativeHelperTest, GetTextFromAriaLabelledBy) {
scoped_refptr<dom::Element> target_element = document()->CreateElement("div");
target_element->AppendChild(document()->CreateTextNode("labelledby target"));
target_element->set_id("target_element");
document()->AppendChild(target_element);
scoped_refptr<dom::Element> labelledby_element =
document()->CreateElement("div");
labelledby_element->SetAttribute(base::Tokens::aria_labelledby().c_str(),
"target_element");
document()->AppendChild(labelledby_element);
EXPECT_TRUE(text_alternative_helper_.TryAppendFromLabelledByOrDescribedBy(
labelledby_element, base::Tokens::aria_labelledby()));
EXPECT_STREQ("labelledby target",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, InvalidLabelledByReference) {
scoped_refptr<dom::Element> target_element = document()->CreateElement("div");
target_element->AppendChild(document()->CreateTextNode("labelledby target"));
target_element->set_id("target_element");
document()->AppendChild(target_element);
scoped_refptr<dom::Element> labelledby_element =
document()->CreateElement("div");
labelledby_element->SetAttribute(base::Tokens::aria_labelledby().c_str(),
"bad_reference");
document()->AppendChild(labelledby_element);
EXPECT_FALSE(text_alternative_helper_.TryAppendFromLabelledByOrDescribedBy(
labelledby_element, base::Tokens::aria_labelledby()));
EXPECT_TRUE(text_alternative_helper_.GetTextAlternative().empty());
}
TEST_F(TextAlternativeHelperTest, MultipleLabelledByReferences) {
scoped_refptr<dom::Element> target_element = document()->CreateElement("div");
target_element->AppendChild(document()->CreateTextNode("target1"));
target_element->set_id("target_element1");
document()->AppendChild(target_element);
target_element = document()->CreateElement("div");
target_element->AppendChild(document()->CreateTextNode("target2"));
target_element->set_id("target_element2");
document()->AppendChild(target_element);
target_element = document()->CreateElement("div");
target_element->AppendChild(document()->CreateTextNode("target3"));
target_element->set_id("target_element3");
document()->AppendChild(target_element);
scoped_refptr<dom::Element> labelledby_element =
document()->CreateElement("div");
labelledby_element->SetAttribute(
base::Tokens::aria_labelledby().c_str(),
"target_element1 target_element2 bad_reference target_element3");
document()->AppendChild(labelledby_element);
EXPECT_TRUE(text_alternative_helper_.TryAppendFromLabelledByOrDescribedBy(
labelledby_element, base::Tokens::aria_labelledby()));
EXPECT_STREQ("target1 target2 target3",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, LabelledByReferencesSelf) {
scoped_refptr<dom::Element> target_element = document()->CreateElement("div");
target_element->AppendChild(document()->CreateTextNode("other-text"));
target_element->set_id("other_id");
document()->AppendChild(target_element);
scoped_refptr<dom::Element> labelledby_element =
document()->CreateElement("div");
labelledby_element->set_id("self_id");
labelledby_element->SetAttribute(base::Tokens::aria_label().c_str(),
"self-label");
labelledby_element->SetAttribute(base::Tokens::aria_labelledby().c_str(),
"other_id self_id");
document()->AppendChild(labelledby_element);
EXPECT_TRUE(text_alternative_helper_.TryAppendFromLabelledByOrDescribedBy(
labelledby_element, base::Tokens::aria_labelledby()));
EXPECT_STREQ("other-text self-label",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, NoRecursiveLabelledBy) {
scoped_refptr<dom::Element> element = document()->CreateElement("div");
element->SetAttribute(base::Tokens::aria_labelledby().c_str(),
"first_labelled_by_id");
document()->AppendChild(element);
scoped_refptr<dom::Element> first_labelledby_element =
document()->CreateElement("div");
first_labelledby_element->AppendChild(
document()->CreateTextNode("first-labelledby-text-contents"));
first_labelledby_element->set_id("first_labelled_by_id");
first_labelledby_element->SetAttribute(
base::Tokens::aria_labelledby().c_str(), "second_labelled_by_id");
document()->AppendChild(first_labelledby_element);
scoped_refptr<dom::Element> second_labelledby_element =
document()->CreateElement("div");
second_labelledby_element->AppendChild(
document()->CreateTextNode("second-labelledby-text-contents"));
second_labelledby_element->set_id("second_labelled_by_id");
document()->AppendChild(second_labelledby_element);
// In the non-recursive case, we should follow the labelledby attribute.
text_alternative_helper_.AppendTextAlternative(first_labelledby_element);
EXPECT_STREQ("second-labelledby-text-contents",
text_alternative_helper_.GetTextAlternative().c_str());
// In the recursive case, we should not follow the second labelledby
// attribute.
text_alternative_helper_ = TextAlternativeHelper();
text_alternative_helper_.AppendTextAlternative(element);
EXPECT_STREQ("first-labelledby-text-contents",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, GetTextFromSubtree) {
scoped_refptr<dom::Element> element = document()->CreateElement("div");
document()->AppendChild(element);
scoped_refptr<dom::Element> child = document()->CreateElement("div");
child->AppendChild(document()->CreateTextNode("child1-text"));
element->AppendChild(child);
scoped_refptr<dom::Element> child_element = document()->CreateElement("div");
element->AppendChild(child_element);
child = document()->CreateElement("div");
child->AppendChild(document()->CreateTextNode("child2-text"));
child_element->AppendChild(child);
child = document()->CreateElement("div");
child->AppendChild(document()->CreateTextNode("child3-text"));
child_element->AppendChild(child);
text_alternative_helper_.AppendTextAlternative(element);
EXPECT_STREQ("child1-text child2-text child3-text",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, DontFollowReferenceLoops) {
scoped_refptr<dom::Element> element = document()->CreateElement("div");
element->set_id("root_element_id");
document()->AppendChild(element);
scoped_refptr<dom::Element> child_element1 = document()->CreateElement("div");
child_element1->SetAttribute(base::Tokens::aria_labelledby().c_str(),
"root_element_id");
element->AppendChild(child_element1);
scoped_refptr<dom::Element> child_element2 = document()->CreateElement("div");
child_element1->AppendChild(child_element2);
child_element2->AppendChild(document()->CreateTextNode("child2-text"));
text_alternative_helper_.AppendTextAlternative(element);
EXPECT_STREQ("child2-text",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, GetTextFromAriaDescribedBy) {
scoped_refptr<dom::Element> target_element = document()->CreateElement("div");
target_element->AppendChild(document()->CreateTextNode("describedby target"));
target_element->set_id("target_element");
document()->AppendChild(target_element);
scoped_refptr<dom::Element> describedby_element =
document()->CreateElement("div");
describedby_element->SetAttribute(base::Tokens::aria_describedby().c_str(),
"target_element");
document()->AppendChild(describedby_element);
EXPECT_TRUE(text_alternative_helper_.TryAppendFromLabelledByOrDescribedBy(
describedby_element, base::Tokens::aria_describedby()));
EXPECT_STREQ("describedby target",
text_alternative_helper_.GetTextAlternative().c_str());
}
TEST_F(TextAlternativeHelperTest, HasBothLabelledByAndDescribedBy) {
// aria-describedby is ignored in this case.
scoped_refptr<dom::Element> element = document()->CreateElement("div");
document()->AppendChild(element);
element->SetAttribute(base::Tokens::aria_labelledby().c_str(), "calendar");
element->SetAttribute(base::Tokens::aria_describedby().c_str(), "info");
scoped_refptr<dom::Element> labelledby_element =
document()->CreateElement("div");
labelledby_element->set_id("calendar");
labelledby_element->AppendChild(document()->CreateTextNode("Calendar"));
element->AppendChild(labelledby_element);
scoped_refptr<dom::Element> describedby_element =
document()->CreateElement("div");
describedby_element->set_id("info");
describedby_element->AppendChild(
document()->CreateTextNode("Calendar content description."));
element->AppendChild(describedby_element);
text_alternative_helper_.AppendTextAlternative(element);
EXPECT_STREQ("Calendar",
text_alternative_helper_.GetTextAlternative().c_str());
}
} // namespace internal
} // namespace accessibility
} // namespace cobalt