mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
314 lines
9.8 KiB
C++
314 lines
9.8 KiB
C++
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Tests for the command parser.
|
|
|
|
#include "base/logging.h"
|
|
#include "base/memory/scoped_ptr.h"
|
|
#include "gpu/command_buffer/service/cmd_parser.h"
|
|
#include "gpu/command_buffer/service/mocks.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace gpu {
|
|
|
|
using testing::_;
|
|
using testing::Invoke;
|
|
using testing::Mock;
|
|
using testing::Return;
|
|
using testing::Sequence;
|
|
using testing::SetArgPointee;
|
|
using testing::Truly;
|
|
|
|
// Test fixture for CommandParser test - Creates a mock AsyncAPIInterface, and
|
|
// a fixed size memory buffer. Also provides a simple API to create a
|
|
// CommandParser.
|
|
class CommandParserTest : public testing::Test {
|
|
protected:
|
|
virtual void SetUp() {
|
|
api_mock_.reset(new AsyncAPIMock(false));
|
|
buffer_entry_count_ = 20;
|
|
buffer_.reset(new CommandBufferEntry[buffer_entry_count_]);
|
|
}
|
|
virtual void TearDown() {}
|
|
|
|
void AddDoCommandsExpect(error::Error _return,
|
|
unsigned int num_commands,
|
|
int num_entries,
|
|
int num_processed) {
|
|
EXPECT_CALL(*api_mock_, DoCommands(num_commands, _, num_entries, _))
|
|
.InSequence(sequence_)
|
|
.WillOnce(DoAll(SetArgPointee<3>(num_processed), Return(_return)));
|
|
}
|
|
|
|
// Creates a parser, with a buffer of the specified size (in entries).
|
|
CommandParser *MakeParser(unsigned int entry_count) {
|
|
size_t shm_size = buffer_entry_count_ *
|
|
sizeof(CommandBufferEntry); // NOLINT
|
|
size_t command_buffer_size = entry_count *
|
|
sizeof(CommandBufferEntry); // NOLINT
|
|
DCHECK_LE(command_buffer_size, shm_size);
|
|
CommandParser* parser = new CommandParser(api_mock());
|
|
|
|
parser->SetBuffer(buffer(), shm_size, 0, command_buffer_size);
|
|
return parser;
|
|
}
|
|
|
|
unsigned int buffer_entry_count() { return 20; }
|
|
AsyncAPIMock *api_mock() { return api_mock_.get(); }
|
|
CommandBufferEntry *buffer() { return buffer_.get(); }
|
|
private:
|
|
unsigned int buffer_entry_count_;
|
|
scoped_ptr<AsyncAPIMock> api_mock_;
|
|
scoped_ptr<CommandBufferEntry[]> buffer_;
|
|
Sequence sequence_;
|
|
};
|
|
|
|
// Tests initialization conditions.
|
|
TEST_F(CommandParserTest, TestInit) {
|
|
scoped_ptr<CommandParser> parser(MakeParser(10));
|
|
EXPECT_EQ(0, parser->get());
|
|
EXPECT_EQ(0, parser->put());
|
|
EXPECT_TRUE(parser->IsEmpty());
|
|
}
|
|
|
|
// Tests simple commands.
|
|
TEST_F(CommandParserTest, TestSimple) {
|
|
scoped_ptr<CommandParser> parser(MakeParser(10));
|
|
CommandBufferOffset put = parser->put();
|
|
CommandHeader header;
|
|
|
|
// add a single command, no args
|
|
header.size = 1;
|
|
header.command = 123;
|
|
buffer()[put++].value_header = header;
|
|
parser->set_put(put);
|
|
EXPECT_EQ(put, parser->put());
|
|
|
|
AddDoCommandsExpect(error::kNoError, 1, 1, 1);
|
|
EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
|
|
EXPECT_EQ(put, parser->get());
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
|
|
// add a single command, 2 args
|
|
header.size = 3;
|
|
header.command = 456;
|
|
buffer()[put++].value_header = header;
|
|
buffer()[put++].value_int32 = 2134;
|
|
buffer()[put++].value_float = 1.f;
|
|
parser->set_put(put);
|
|
EXPECT_EQ(put, parser->put());
|
|
|
|
AddDoCommandsExpect(error::kNoError, 1, 3, 3);
|
|
EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
|
|
EXPECT_EQ(put, parser->get());
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
}
|
|
|
|
// Tests having multiple commands in the buffer.
|
|
TEST_F(CommandParserTest, TestMultipleCommands) {
|
|
scoped_ptr<CommandParser> parser(MakeParser(10));
|
|
CommandBufferOffset put = parser->put();
|
|
CommandHeader header;
|
|
|
|
// add 2 commands, test with single ProcessCommands()
|
|
header.size = 2;
|
|
header.command = 789;
|
|
buffer()[put++].value_header = header;
|
|
buffer()[put++].value_int32 = 5151;
|
|
|
|
CommandBufferOffset put_cmd2 = put;
|
|
header.size = 2;
|
|
header.command = 876;
|
|
buffer()[put++].value_header = header;
|
|
buffer()[put++].value_int32 = 3434;
|
|
parser->set_put(put);
|
|
EXPECT_EQ(put, parser->put());
|
|
|
|
// Process up to 1 command. 4 entries remaining.
|
|
AddDoCommandsExpect(error::kNoError, 1, 4, 2);
|
|
EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
|
|
EXPECT_EQ(put_cmd2, parser->get());
|
|
|
|
// Process up to 1 command. 2 entries remaining.
|
|
AddDoCommandsExpect(error::kNoError, 1, 2, 2);
|
|
EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
|
|
EXPECT_EQ(put, parser->get());
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
|
|
// add 2 commands again, test with ProcessAllCommands()
|
|
header.size = 2;
|
|
header.command = 123;
|
|
buffer()[put++].value_header = header;
|
|
buffer()[put++].value_int32 = 5656;
|
|
|
|
header.size = 2;
|
|
header.command = 321;
|
|
buffer()[put++].value_header = header;
|
|
buffer()[put++].value_int32 = 7878;
|
|
parser->set_put(put);
|
|
EXPECT_EQ(put, parser->put());
|
|
|
|
// 4 entries remaining.
|
|
AddDoCommandsExpect(
|
|
error::kNoError, CommandParser::kParseCommandsSlice, 4, 4);
|
|
EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
|
|
EXPECT_EQ(put, parser->get());
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
}
|
|
|
|
// Tests that the parser will wrap correctly at the end of the buffer.
|
|
TEST_F(CommandParserTest, TestWrap) {
|
|
scoped_ptr<CommandParser> parser(MakeParser(5));
|
|
CommandBufferOffset put = parser->put();
|
|
CommandHeader header;
|
|
|
|
// add 3 commands with no args (1 word each)
|
|
for (unsigned int i = 0; i < 3; ++i) {
|
|
header.size = 1;
|
|
header.command = i;
|
|
buffer()[put++].value_header = header;
|
|
}
|
|
parser->set_put(put);
|
|
EXPECT_EQ(put, parser->put());
|
|
|
|
// Process up to 10 commands. 3 entries remaining to put.
|
|
AddDoCommandsExpect(error::kNoError, 10, 3, 3);
|
|
EXPECT_EQ(error::kNoError, parser->ProcessCommands(10));
|
|
EXPECT_EQ(put, parser->get());
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
|
|
// add 1 command with 1 arg (2 words). That should put us at the end of the
|
|
// buffer.
|
|
header.size = 2;
|
|
header.command = 3;
|
|
buffer()[put++].value_header = header;
|
|
buffer()[put++].value_int32 = 5;
|
|
|
|
DCHECK_EQ(5, put);
|
|
put = 0;
|
|
|
|
// add 1 command with 1 arg (2 words).
|
|
header.size = 2;
|
|
header.command = 4;
|
|
buffer()[put++].value_header = header;
|
|
buffer()[put++].value_int32 = 6;
|
|
|
|
// 2 entries remaining to end of buffer.
|
|
AddDoCommandsExpect(
|
|
error::kNoError, CommandParser::kParseCommandsSlice, 2, 2);
|
|
// 2 entries remaining to put.
|
|
AddDoCommandsExpect(
|
|
error::kNoError, CommandParser::kParseCommandsSlice, 2, 2);
|
|
parser->set_put(put);
|
|
EXPECT_EQ(put, parser->put());
|
|
|
|
EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
|
|
EXPECT_EQ(put, parser->get());
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
}
|
|
|
|
// Tests error conditions.
|
|
TEST_F(CommandParserTest, TestError) {
|
|
const unsigned int kNumEntries = 5;
|
|
scoped_ptr<CommandParser> parser(MakeParser(kNumEntries));
|
|
CommandBufferOffset put = parser->put();
|
|
CommandHeader header;
|
|
|
|
EXPECT_FALSE(parser->set_get(-1));
|
|
EXPECT_FALSE(parser->set_get(kNumEntries));
|
|
|
|
// Generate a command with size 0.
|
|
header.size = 0;
|
|
header.command = 3;
|
|
buffer()[put++].value_header = header;
|
|
|
|
parser->set_put(put);
|
|
EXPECT_EQ(put, parser->put());
|
|
|
|
AddDoCommandsExpect(
|
|
error::kInvalidSize, CommandParser::kParseCommandsSlice, 1, 0);
|
|
EXPECT_EQ(error::kInvalidSize,
|
|
parser->ProcessAllCommands());
|
|
// check that no DoCommand call was made.
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
|
|
parser.reset(MakeParser(5));
|
|
put = parser->put();
|
|
|
|
// Generate a command with size 6, extends beyond the end of the buffer.
|
|
header.size = 6;
|
|
header.command = 3;
|
|
buffer()[put++].value_header = header;
|
|
|
|
parser->set_put(put);
|
|
EXPECT_EQ(put, parser->put());
|
|
|
|
AddDoCommandsExpect(
|
|
error::kOutOfBounds, CommandParser::kParseCommandsSlice, 1, 0);
|
|
EXPECT_EQ(error::kOutOfBounds,
|
|
parser->ProcessAllCommands());
|
|
// check that no DoCommand call was made.
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
|
|
parser.reset(MakeParser(5));
|
|
put = parser->put();
|
|
|
|
// Generates 2 commands.
|
|
header.size = 1;
|
|
header.command = 3;
|
|
buffer()[put++].value_header = header;
|
|
CommandBufferOffset put_post_fail = put;
|
|
header.size = 1;
|
|
header.command = 4;
|
|
buffer()[put++].value_header = header;
|
|
|
|
parser->set_put(put);
|
|
EXPECT_EQ(put, parser->put());
|
|
// have the first command fail to parse.
|
|
AddDoCommandsExpect(
|
|
error::kUnknownCommand, CommandParser::kParseCommandsSlice, 2, 1);
|
|
EXPECT_EQ(error::kUnknownCommand,
|
|
parser->ProcessAllCommands());
|
|
// check that only one command was executed, and that get reflects that
|
|
// correctly.
|
|
EXPECT_EQ(put_post_fail, parser->get());
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
// make the second one succeed, and check that the parser recovered fine.
|
|
AddDoCommandsExpect(
|
|
error::kNoError, CommandParser::kParseCommandsSlice, 1, 1);
|
|
EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
|
|
EXPECT_EQ(put, parser->get());
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
}
|
|
|
|
TEST_F(CommandParserTest, SetBuffer) {
|
|
scoped_ptr<CommandParser> parser(MakeParser(3));
|
|
CommandBufferOffset put = parser->put();
|
|
CommandHeader header;
|
|
|
|
// add a single command, no args
|
|
header.size = 2;
|
|
header.command = 123;
|
|
buffer()[put++].value_header = header;
|
|
buffer()[put++].value_int32 = 456;
|
|
parser->set_put(put);
|
|
|
|
AddDoCommandsExpect(
|
|
error::kNoError, CommandParser::kParseCommandsSlice, 2, 2);
|
|
EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
|
|
// We should have advanced 2 entries
|
|
EXPECT_EQ(2, parser->get());
|
|
Mock::VerifyAndClearExpectations(api_mock());
|
|
|
|
scoped_ptr<CommandBufferEntry[]> buffer2(new CommandBufferEntry[2]);
|
|
parser->SetBuffer(
|
|
buffer2.get(), sizeof(CommandBufferEntry) * 2, 0,
|
|
sizeof(CommandBufferEntry) * 2);
|
|
// The put and get should have reset to 0.
|
|
EXPECT_EQ(0, parser->get());
|
|
EXPECT_EQ(0, parser->put());
|
|
}
|
|
|
|
} // namespace gpu
|