blob: 1ca85898fa70da4b5a9340cf3d806576666ab1db [file] [log] [blame]
/*
* Copyright (C) 2013, Opera Software ASA. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/core/html/track/vtt/buffered_line_reader.h"
#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
TEST(BufferedLineReaderTest, Constructor) {
BufferedLineReader reader;
ASSERT_FALSE(reader.IsAtEndOfStream());
String line;
ASSERT_FALSE(reader.GetLine(line));
}
TEST(BufferedLineReaderTest, EOSNoInput) {
BufferedLineReader reader;
String line;
ASSERT_FALSE(reader.GetLine(line));
reader.SetEndOfStream();
// No input observed, so still no line.
ASSERT_FALSE(reader.GetLine(line));
}
TEST(BufferedLineReaderTest, EOSInput) {
BufferedLineReader reader;
reader.Append("A");
reader.SetEndOfStream();
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "A");
}
TEST(BufferedLineReaderTest, EOSMultipleReads_1) {
BufferedLineReader reader;
reader.Append("A");
reader.SetEndOfStream();
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "A");
// No more lines returned.
ASSERT_FALSE(reader.GetLine(line));
ASSERT_FALSE(reader.GetLine(line));
}
TEST(BufferedLineReaderTest, EOSMultipleReads_2) {
BufferedLineReader reader;
reader.Append("A\n");
reader.SetEndOfStream();
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "A");
// No more lines returned.
ASSERT_FALSE(reader.GetLine(line));
ASSERT_FALSE(reader.GetLine(line));
}
TEST(BufferedLineReaderTest, LineEndingCR) {
BufferedLineReader reader;
reader.Append("X\rY");
reader.SetEndOfStream();
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "X");
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "Y");
}
TEST(BufferedLineReaderTest, LineEndingCR_EOS) {
BufferedLineReader reader;
reader.Append("X\r");
reader.SetEndOfStream();
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "X");
ASSERT_FALSE(reader.GetLine(line));
}
TEST(BufferedLineReaderTest, LineEndingLF) {
BufferedLineReader reader;
reader.Append("X\nY");
reader.SetEndOfStream();
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "X");
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "Y");
}
TEST(BufferedLineReaderTest, LineEndingLF_EOS) {
BufferedLineReader reader;
reader.Append("X\n");
reader.SetEndOfStream();
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "X");
ASSERT_FALSE(reader.GetLine(line));
}
TEST(BufferedLineReaderTest, LineEndingCRLF) {
BufferedLineReader reader;
reader.Append("X\r\nY");
reader.SetEndOfStream();
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "X");
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "Y");
}
TEST(BufferedLineReaderTest, LineEndingCRLF_EOS) {
BufferedLineReader reader;
reader.Append("X\r\n");
reader.SetEndOfStream();
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "X");
ASSERT_FALSE(reader.GetLine(line));
}
enum NewlineType { kCr, kLf, kCrLf };
String LineBreakString(NewlineType type) {
static const char kBreakStrings[] = "\r\n";
return String(type == kLf ? kBreakStrings + 1 : kBreakStrings,
type == kCrLf ? 2u : 1u);
}
String MakeTestData(const char** lines, const NewlineType* breaks, int count) {
StringBuilder builder;
for (int i = 0; i < count; ++i) {
builder.Append(lines[i]);
builder.Append(LineBreakString(breaks[i]));
}
return builder.ToString();
}
const wtf_size_t kBlockSizes[] = {64, 32, 16, 8, 4, 2, 1, 3,
5, 7, 9, 11, 13, 17, 19, 23};
TEST(BufferedLineReaderTest, BufferSizes) {
const char* lines[] = {"aaaaaaaaaaaaaaaa", "bbbbbbbbbb", "ccccccccccccc", "",
"dddddd", "", "eeeeeeeeee"};
const NewlineType kBreaks[] = {kLf, kLf, kLf, kLf, kLf, kLf, kLf};
const size_t num_test_lines = base::size(lines);
static_assert(num_test_lines == base::size(kBreaks),
"number of test lines and breaks should be the same");
String data = MakeTestData(lines, kBreaks, num_test_lines);
for (size_t k = 0; k < base::size(kBlockSizes); ++k) {
size_t line_count = 0;
BufferedLineReader reader;
wtf_size_t block_size = kBlockSizes[k];
for (wtf_size_t i = 0; i < data.length(); i += block_size) {
reader.Append(data.Substring(i, block_size));
String line;
while (reader.GetLine(line)) {
ASSERT_LT(line_count, num_test_lines);
ASSERT_EQ(line, lines[line_count++]);
}
}
ASSERT_EQ(line_count, num_test_lines);
}
}
TEST(BufferedLineReaderTest, BufferSizesMixedEndings) {
const char* lines[] = {
"aaaaaaaaaaaaaaaa", "bbbbbbbbbb", "ccccccccccccc", "",
"dddddd", "eeeeeeeeee", "fffffffffffffffffff"};
const NewlineType kBreaks[] = {kCr, kLf, kCrLf, kCr, kLf, kCrLf, kLf};
const size_t num_test_lines = base::size(lines);
static_assert(num_test_lines == base::size(kBreaks),
"number of test lines and breaks should be the same");
String data = MakeTestData(lines, kBreaks, num_test_lines);
for (size_t k = 0; k < base::size(kBlockSizes); ++k) {
size_t line_count = 0;
BufferedLineReader reader;
wtf_size_t block_size = kBlockSizes[k];
for (wtf_size_t i = 0; i < data.length(); i += block_size) {
reader.Append(data.Substring(i, block_size));
String line;
while (reader.GetLine(line)) {
ASSERT_LT(line_count, num_test_lines);
ASSERT_EQ(line, lines[line_count++]);
}
}
ASSERT_EQ(line_count, num_test_lines);
}
}
TEST(BufferedLineReaderTest, BufferBoundaryInCRLF_1) {
BufferedLineReader reader;
reader.Append("X\r");
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "X");
reader.Append("\n");
ASSERT_FALSE(reader.GetLine(line));
}
TEST(BufferedLineReaderTest, BufferBoundaryInCRLF_2) {
BufferedLineReader reader;
reader.Append("X\r");
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "X");
ASSERT_FALSE(reader.GetLine(line));
reader.Append("\n");
ASSERT_FALSE(reader.GetLine(line));
reader.Append("Y\n");
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line, "Y");
}
TEST(BufferedLineReaderTest, NormalizedNUL) {
BufferedLineReader reader;
reader.Append(String("X\0Y\n", 4u));
String line;
ASSERT_TRUE(reader.GetLine(line));
ASSERT_EQ(line[1], kReplacementCharacter);
}
} // namespace blink