1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Tests for the command parser. 6 7 #include "base/logging.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "gpu/command_buffer/service/cmd_parser.h" 10 #include "gpu/command_buffer/service/mocks.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 13 namespace gpu { 14 15 using testing::Return; 16 using testing::Mock; 17 using testing::Truly; 18 using testing::Sequence; 19 using testing::_; 20 21 // Test fixture for CommandParser test - Creates a mock AsyncAPIInterface, and 22 // a fixed size memory buffer. Also provides a simple API to create a 23 // CommandParser. 24 class CommandParserTest : public testing::Test { 25 protected: 26 virtual void SetUp() { 27 api_mock_.reset(new AsyncAPIMock); 28 buffer_entry_count_ = 20; 29 buffer_.reset(new CommandBufferEntry[buffer_entry_count_]); 30 } 31 virtual void TearDown() {} 32 33 // Adds a DoCommand expectation in the mock. 34 void AddDoCommandExpect(error::Error _return, 35 unsigned int command, 36 unsigned int arg_count, 37 CommandBufferEntry *args) { 38 EXPECT_CALL(*api_mock(), DoCommand(command, arg_count, 39 Truly(AsyncAPIMock::IsArgs(arg_count, args)))) 40 .InSequence(sequence_) 41 .WillOnce(Return(_return)); 42 } 43 44 // Creates a parser, with a buffer of the specified size (in entries). 45 CommandParser *MakeParser(unsigned int entry_count) { 46 size_t shm_size = buffer_entry_count_ * 47 sizeof(CommandBufferEntry); // NOLINT 48 size_t command_buffer_size = entry_count * 49 sizeof(CommandBufferEntry); // NOLINT 50 DCHECK_LE(command_buffer_size, shm_size); 51 CommandParser* parser = new CommandParser(api_mock()); 52 53 parser->SetBuffer(buffer(), shm_size, 0, command_buffer_size); 54 return parser; 55 } 56 57 unsigned int buffer_entry_count() { return 20; } 58 AsyncAPIMock *api_mock() { return api_mock_.get(); } 59 CommandBufferEntry *buffer() { return buffer_.get(); } 60 private: 61 unsigned int buffer_entry_count_; 62 scoped_ptr<AsyncAPIMock> api_mock_; 63 scoped_ptr<CommandBufferEntry[]> buffer_; 64 Sequence sequence_; 65 }; 66 67 // Tests initialization conditions. 68 TEST_F(CommandParserTest, TestInit) { 69 scoped_ptr<CommandParser> parser(MakeParser(10)); 70 EXPECT_EQ(0, parser->get()); 71 EXPECT_EQ(0, parser->put()); 72 EXPECT_TRUE(parser->IsEmpty()); 73 } 74 75 // Tests simple commands. 76 TEST_F(CommandParserTest, TestSimple) { 77 scoped_ptr<CommandParser> parser(MakeParser(10)); 78 CommandBufferOffset put = parser->put(); 79 CommandHeader header; 80 81 // add a single command, no args 82 header.size = 1; 83 header.command = 123; 84 buffer()[put++].value_header = header; 85 86 parser->set_put(put); 87 EXPECT_EQ(put, parser->put()); 88 89 AddDoCommandExpect(error::kNoError, 123, 0, NULL); 90 EXPECT_EQ(error::kNoError, parser->ProcessCommand()); 91 EXPECT_EQ(put, parser->get()); 92 Mock::VerifyAndClearExpectations(api_mock()); 93 94 // add a single command, 2 args 95 header.size = 3; 96 header.command = 456; 97 buffer()[put++].value_header = header; 98 buffer()[put++].value_int32 = 2134; 99 buffer()[put++].value_float = 1.f; 100 101 parser->set_put(put); 102 EXPECT_EQ(put, parser->put()); 103 104 CommandBufferEntry param_array[2]; 105 param_array[0].value_int32 = 2134; 106 param_array[1].value_float = 1.f; 107 AddDoCommandExpect(error::kNoError, 456, 2, param_array); 108 EXPECT_EQ(error::kNoError, parser->ProcessCommand()); 109 EXPECT_EQ(put, parser->get()); 110 Mock::VerifyAndClearExpectations(api_mock()); 111 } 112 113 // Tests having multiple commands in the buffer. 114 TEST_F(CommandParserTest, TestMultipleCommands) { 115 scoped_ptr<CommandParser> parser(MakeParser(10)); 116 CommandBufferOffset put = parser->put(); 117 CommandHeader header; 118 119 // add 2 commands, test with single ProcessCommand() 120 header.size = 2; 121 header.command = 789; 122 buffer()[put++].value_header = header; 123 buffer()[put++].value_int32 = 5151; 124 125 CommandBufferOffset put_cmd2 = put; 126 header.size = 2; 127 header.command = 876; 128 buffer()[put++].value_header = header; 129 buffer()[put++].value_int32 = 3434; 130 131 parser->set_put(put); 132 EXPECT_EQ(put, parser->put()); 133 134 CommandBufferEntry param_array[2]; 135 param_array[0].value_int32 = 5151; 136 AddDoCommandExpect(error::kNoError, 789, 1, param_array); 137 param_array[1].value_int32 = 3434; 138 AddDoCommandExpect(error::kNoError, 876, 1, 139 param_array+1); 140 141 EXPECT_EQ(error::kNoError, parser->ProcessCommand()); 142 EXPECT_EQ(put_cmd2, parser->get()); 143 EXPECT_EQ(error::kNoError, parser->ProcessCommand()); 144 EXPECT_EQ(put, parser->get()); 145 Mock::VerifyAndClearExpectations(api_mock()); 146 147 // add 2 commands again, test with ProcessAllCommands() 148 header.size = 2; 149 header.command = 123; 150 buffer()[put++].value_header = header; 151 buffer()[put++].value_int32 = 5656; 152 153 header.size = 2; 154 header.command = 321; 155 buffer()[put++].value_header = header; 156 buffer()[put++].value_int32 = 7878; 157 158 parser->set_put(put); 159 EXPECT_EQ(put, parser->put()); 160 161 param_array[0].value_int32 = 5656; 162 AddDoCommandExpect(error::kNoError, 123, 1, param_array); 163 param_array[1].value_int32 = 7878; 164 AddDoCommandExpect(error::kNoError, 321, 1, 165 param_array+1); 166 167 EXPECT_EQ(error::kNoError, parser->ProcessAllCommands()); 168 EXPECT_EQ(put, parser->get()); 169 Mock::VerifyAndClearExpectations(api_mock()); 170 } 171 172 // Tests that the parser will wrap correctly at the end of the buffer. 173 TEST_F(CommandParserTest, TestWrap) { 174 scoped_ptr<CommandParser> parser(MakeParser(5)); 175 CommandBufferOffset put = parser->put(); 176 CommandHeader header; 177 178 // add 3 commands with no args (1 word each) 179 for (unsigned int i = 0; i < 3; ++i) { 180 header.size = 1; 181 header.command = i; 182 buffer()[put++].value_header = header; 183 AddDoCommandExpect(error::kNoError, i, 0, NULL); 184 } 185 parser->set_put(put); 186 EXPECT_EQ(put, parser->put()); 187 EXPECT_EQ(error::kNoError, parser->ProcessAllCommands()); 188 EXPECT_EQ(put, parser->get()); 189 Mock::VerifyAndClearExpectations(api_mock()); 190 191 // add 1 command with 1 arg (2 words). That should put us at the end of the 192 // buffer. 193 header.size = 2; 194 header.command = 3; 195 buffer()[put++].value_header = header; 196 buffer()[put++].value_int32 = 5; 197 CommandBufferEntry param; 198 param.value_int32 = 5; 199 AddDoCommandExpect(error::kNoError, 3, 1, ¶m); 200 201 DCHECK_EQ(5, put); 202 put = 0; 203 parser->set_put(put); 204 EXPECT_EQ(put, parser->put()); 205 EXPECT_EQ(error::kNoError, parser->ProcessAllCommands()); 206 EXPECT_EQ(put, parser->get()); 207 Mock::VerifyAndClearExpectations(api_mock()); 208 209 // add 1 command with 1 arg (2 words). 210 header.size = 2; 211 header.command = 4; 212 buffer()[put++].value_header = header; 213 buffer()[put++].value_int32 = 6; 214 param.value_int32 = 6; 215 AddDoCommandExpect(error::kNoError, 4, 1, ¶m); 216 parser->set_put(put); 217 EXPECT_EQ(put, parser->put()); 218 EXPECT_EQ(error::kNoError, parser->ProcessAllCommands()); 219 EXPECT_EQ(put, parser->get()); 220 Mock::VerifyAndClearExpectations(api_mock()); 221 } 222 223 // Tests error conditions. 224 TEST_F(CommandParserTest, TestError) { 225 const unsigned int kNumEntries = 5; 226 scoped_ptr<CommandParser> parser(MakeParser(kNumEntries)); 227 CommandBufferOffset put = parser->put(); 228 CommandHeader header; 229 230 EXPECT_FALSE(parser->set_get(-1)); 231 EXPECT_FALSE(parser->set_get(kNumEntries)); 232 233 // Generate a command with size 0. 234 header.size = 0; 235 header.command = 3; 236 buffer()[put++].value_header = header; 237 238 parser->set_put(put); 239 EXPECT_EQ(put, parser->put()); 240 EXPECT_EQ(error::kInvalidSize, 241 parser->ProcessAllCommands()); 242 // check that no DoCommand call was made. 243 Mock::VerifyAndClearExpectations(api_mock()); 244 245 parser.reset(MakeParser(5)); 246 put = parser->put(); 247 248 // Generate a command with size 6, extends beyond the end of the buffer. 249 header.size = 6; 250 header.command = 3; 251 buffer()[put++].value_header = header; 252 253 parser->set_put(put); 254 EXPECT_EQ(put, parser->put()); 255 EXPECT_EQ(error::kOutOfBounds, 256 parser->ProcessAllCommands()); 257 // check that no DoCommand call was made. 258 Mock::VerifyAndClearExpectations(api_mock()); 259 260 parser.reset(MakeParser(5)); 261 put = parser->put(); 262 263 // Generates 2 commands. 264 header.size = 1; 265 header.command = 3; 266 buffer()[put++].value_header = header; 267 CommandBufferOffset put_post_fail = put; 268 header.size = 1; 269 header.command = 4; 270 buffer()[put++].value_header = header; 271 272 parser->set_put(put); 273 EXPECT_EQ(put, parser->put()); 274 // have the first command fail to parse. 275 AddDoCommandExpect(error::kUnknownCommand, 3, 0, NULL); 276 EXPECT_EQ(error::kUnknownCommand, 277 parser->ProcessAllCommands()); 278 // check that only one command was executed, and that get reflects that 279 // correctly. 280 EXPECT_EQ(put_post_fail, parser->get()); 281 Mock::VerifyAndClearExpectations(api_mock()); 282 // make the second one succeed, and check that the parser recovered fine. 283 AddDoCommandExpect(error::kNoError, 4, 0, NULL); 284 EXPECT_EQ(error::kNoError, parser->ProcessAllCommands()); 285 EXPECT_EQ(put, parser->get()); 286 Mock::VerifyAndClearExpectations(api_mock()); 287 } 288 289 TEST_F(CommandParserTest, SetBuffer) { 290 scoped_ptr<CommandParser> parser(MakeParser(3)); 291 CommandBufferOffset put = parser->put(); 292 CommandHeader header; 293 294 // add a single command, no args 295 header.size = 2; 296 header.command = 123; 297 buffer()[put++].value_header = header; 298 buffer()[put++].value_int32 = 456; 299 300 CommandBufferEntry param_array[1]; 301 param_array[0].value_int32 = 456; 302 303 parser->set_put(put); 304 AddDoCommandExpect(error::kNoError, 123, 1, param_array); 305 EXPECT_EQ(error::kNoError, parser->ProcessAllCommands()); 306 // We should have advanced 2 entries 307 EXPECT_EQ(2, parser->get()); 308 Mock::VerifyAndClearExpectations(api_mock()); 309 310 scoped_ptr<CommandBufferEntry[]> buffer2(new CommandBufferEntry[2]); 311 parser->SetBuffer( 312 buffer2.get(), sizeof(CommandBufferEntry) * 2, 0, 313 sizeof(CommandBufferEntry) * 2); 314 // The put and get should have reset to 0. 315 EXPECT_EQ(0, parser->get()); 316 EXPECT_EQ(0, parser->put()); 317 } 318 319 } // namespace gpu 320