diff options
Diffstat (limited to 'o3d/command_buffer/service/cmd_parser_test.cc')
-rw-r--r-- | o3d/command_buffer/service/cmd_parser_test.cc | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/o3d/command_buffer/service/cmd_parser_test.cc b/o3d/command_buffer/service/cmd_parser_test.cc new file mode 100644 index 0000000..153c20a --- /dev/null +++ b/o3d/command_buffer/service/cmd_parser_test.cc @@ -0,0 +1,314 @@ +/* + * Copyright 2009, Google Inc. + * 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. + */ + + +// Tests for the command parser. + +#include "tests/common/win/testing_common.h" +#include "command_buffer/service/cmd_parser.h" +#include "command_buffer/service/mocks.h" +#include "base/scoped_ptr.h" + +namespace command_buffer { + +using testing::Return; +using testing::Mock; +using testing::Truly; +using testing::Sequence; +using testing::_; + +// 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); + buffer_entry_count_ = 20; + buffer_.reset(new CommandBufferEntry[buffer_entry_count_]); + } + virtual void TearDown() {} + + // Adds a DoCommand expectation in the mock. + void AddDoCommandExpect(parse_error::ParseError _return, + unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args) { + EXPECT_CALL(*api_mock(), DoCommand(command, arg_count, + Truly(AsyncAPIMock::IsArgs(arg_count, args)))) + .InSequence(sequence_) + .WillOnce(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); + return new CommandParser(buffer(), + shm_size, + 0, + command_buffer_size, + 0, + api_mock()); + } + + 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_array<CommandBufferEntry> buffer_; + Sequence sequence_; +}; + +// Tests initialization conditions. +TEST_F(CommandParserTest, TestInit) { + scoped_ptr<CommandParser> parser(MakeParser(10)); + EXPECT_EQ(0u, parser->get()); + EXPECT_EQ(0u, 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()); + + AddDoCommandExpect(parse_error::kParseNoError, 123, 0, NULL); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand()); + 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()); + + CommandBufferEntry param_array[2]; + param_array[0].value_int32 = 2134; + param_array[1].value_float = 1.f; + AddDoCommandExpect(parse_error::kParseNoError, 456, 2, param_array); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand()); + 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 ProcessCommand() + 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 = 2121; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 3434; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + + CommandBufferEntry param_array[2]; + param_array[0].value_int32 = 5151; + AddDoCommandExpect(parse_error::kParseNoError, 789, 1, param_array); + param_array[1].value_int32 = 3434; + AddDoCommandExpect(parse_error::kParseNoError, 2121, 1, + param_array+1); + + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand()); + EXPECT_EQ(put_cmd2, parser->get()); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + + // add 2 commands again, test with ProcessAllCommands() + header.size = 2; + header.command = 4545; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 5656; + + header.size = 2; + header.command = 6767; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 7878; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + + param_array[0].value_int32 = 5656; + AddDoCommandExpect(parse_error::kParseNoError, 4545, 1, param_array); + param_array[1].value_int32 = 7878; + AddDoCommandExpect(parse_error::kParseNoError, 6767, 1, + param_array+1); + + EXPECT_EQ(parse_error::kParseNoError, 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; + AddDoCommandExpect(parse_error::kParseNoError, i, 0, NULL); + } + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands()); + 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; + CommandBufferEntry param; + param.value_int32 = 5; + AddDoCommandExpect(parse_error::kParseNoError, 3, 1, ¶m); + + DCHECK_EQ(5u, put); + put = 0; + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + + // add 1 command with 1 arg (2 words). + header.size = 2; + header.command = 4; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 6; + param.value_int32 = 6; + AddDoCommandExpect(parse_error::kParseNoError, 4, 1, ¶m); + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); +} + +// Tests error conditions. +TEST_F(CommandParserTest, TestError) { + scoped_ptr<CommandParser> parser(MakeParser(5)); + CommandBufferOffset put = parser->put(); + CommandHeader header; + + // 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()); + EXPECT_EQ(parse_error::kParseInvalidSize, + 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()); + EXPECT_EQ(parse_error::kParseOutOfBounds, + 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. + AddDoCommandExpect(parse_error::kParseUnknownCommand, 3, 0, NULL); + EXPECT_EQ(parse_error::kParseUnknownCommand, + 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. + AddDoCommandExpect(parse_error::kParseNoError, 4, 0, NULL); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); +} + +} // namespace command_buffer |