1 // Copyright 2008 Google Inc. 2 // Author: Lincoln Smith 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 // Unit tests for struct VCDiffCodeTableData, found in codetable.h. 17 18 #include <config.h> 19 #include "codetable.h" 20 #include "addrcache.h" 21 #include "testing.h" 22 23 namespace open_vcdiff { 24 namespace { 25 26 class CodeTableTest : public testing::Test { 27 protected: 28 CodeTableTest() 29 : code_table_data_(VCDiffCodeTableData::kDefaultCodeTableData) { } 30 31 virtual ~CodeTableTest() { } 32 33 virtual void SetUp() { 34 // Default code table must pass 35 EXPECT_TRUE(ValidateCodeTable()); 36 } 37 38 static void AddExerciseOpcode(unsigned char inst1, 39 unsigned char mode1, 40 unsigned char size1, 41 unsigned char inst2, 42 unsigned char mode2, 43 unsigned char size2, 44 int opcode) { 45 g_exercise_code_table_->inst1[opcode] = inst1; 46 g_exercise_code_table_->mode1[opcode] = mode1; 47 g_exercise_code_table_->size1[opcode] = (inst1 == VCD_NOOP) ? 0 : size1; 48 g_exercise_code_table_->inst2[opcode] = inst2; 49 g_exercise_code_table_->mode2[opcode] = mode2; 50 g_exercise_code_table_->size2[opcode] = (inst2 == VCD_NOOP) ? 0 : size2; 51 } 52 53 static void SetUpTestCase() { 54 g_exercise_code_table_ = new VCDiffCodeTableData; 55 int opcode = 0; 56 for (unsigned char inst_mode1 = 0; 57 inst_mode1 <= VCD_LAST_INSTRUCTION_TYPE + kLastExerciseMode; 58 ++inst_mode1) { 59 unsigned char inst1 = inst_mode1; 60 unsigned char mode1 = 0; 61 if (inst_mode1 > VCD_COPY) { 62 inst1 = VCD_COPY; 63 mode1 = inst_mode1 - VCD_COPY; 64 } 65 for (unsigned char inst_mode2 = 0; 66 inst_mode2 <= VCD_LAST_INSTRUCTION_TYPE + kLastExerciseMode; 67 ++inst_mode2) { 68 unsigned char inst2 = inst_mode2; 69 unsigned char mode2 = 0; 70 if (inst_mode2 > VCD_COPY) { 71 inst2 = VCD_COPY; 72 mode2 = inst_mode2 - VCD_COPY; 73 } 74 AddExerciseOpcode(inst1, mode1, 0, inst2, mode2, 0, opcode++); 75 AddExerciseOpcode(inst1, mode1, 0, inst2, mode2, 255, opcode++); 76 AddExerciseOpcode(inst1, mode1, 255, inst2, mode2, 0, opcode++); 77 AddExerciseOpcode(inst1, mode1, 255, inst2, mode2, 255, opcode++); 78 } 79 } 80 // This is a CHECK rather than an EXPECT because it validates only 81 // the logic of the test, not of the code being tested. 82 CHECK_EQ(VCDiffCodeTableData::kCodeTableSize, opcode); 83 84 EXPECT_TRUE(VCDiffCodeTableData::kDefaultCodeTableData.Validate()); 85 EXPECT_TRUE(g_exercise_code_table_->Validate(kLastExerciseMode)); 86 } 87 88 static void TearDownTestCase() { 89 delete g_exercise_code_table_; 90 } 91 92 void VerifyInstruction(unsigned char opcode, 93 unsigned char inst, 94 unsigned char size, 95 unsigned char mode) { 96 EXPECT_EQ(inst, code_table_data_.inst1[opcode]); 97 EXPECT_EQ(size, code_table_data_.size1[opcode]); 98 EXPECT_EQ(mode, code_table_data_.mode1[opcode]); 99 EXPECT_EQ(VCD_NOOP, code_table_data_.inst2[opcode]); 100 EXPECT_EQ(0, code_table_data_.size2[opcode]); 101 EXPECT_EQ(0, code_table_data_.mode2[opcode]); 102 } 103 104 bool ValidateCodeTable() { 105 return code_table_data_.Validate(); 106 } 107 108 // This value is designed so that the total number of inst values and modes 109 // will equal 8 (VCD_NOOP, VCD_ADD, VCD_RUN, VCD_COPY modes 0 - 4). 110 // Eight combinations of inst and mode, times two possible size values, 111 // squared (because there are two instructions per opcode), makes 112 // exactly 256 possible instruction combinations, which fits kCodeTableSize 113 // (the number of opcodes in the table.) 114 static const int kLastExerciseMode = 4; 115 116 // A code table that exercises as many combinations as possible: 117 // 2 instructions, each is a NOOP, ADD, RUN, or one of 5 copy modes 118 // (== 8 total combinations of inst and mode), and each has 119 // size == 0 or 255 (2 possibilities.) 120 static VCDiffCodeTableData* g_exercise_code_table_; 121 122 // The code table used by the current test. 123 VCDiffCodeTableData code_table_data_; 124 }; 125 126 VCDiffCodeTableData* CodeTableTest::g_exercise_code_table_ = NULL; 127 128 // These tests make sure that ValidateCodeTable() catches particular 129 // error conditions in a custom code table. 130 131 // All possible combinations of inst and mode should have an opcode with size 0. 132 TEST_F(CodeTableTest, MissingCopyMode) { 133 VerifyInstruction(/* opcode */ 131, VCD_COPY, /* size */ 0, /* mode */ 7); 134 code_table_data_.size1[131] = 0xFF; 135 // Now there is no opcode expressing COPY with mode 7 and size 0. 136 EXPECT_FALSE(ValidateCodeTable()); 137 } 138 139 TEST_F(CodeTableTest, MissingAdd) { 140 VerifyInstruction(/* opcode */ 1, VCD_ADD, /* size */ 0, /* mode */ 0); 141 code_table_data_.size1[1] = 0xFF; // Add size 0 => size 255 142 // Now there is no opcode expressing ADD with size 0. 143 EXPECT_FALSE(ValidateCodeTable()); 144 } 145 146 TEST_F(CodeTableTest, MissingRun) { 147 VerifyInstruction(/* opcode */ 0, VCD_RUN, /* size */ 0, /* mode */ 0); 148 code_table_data_.size1[0] = 0xFF; // Run size 0 => size 255 149 // Now there is no opcode expressing RUN with size 0. 150 EXPECT_FALSE(ValidateCodeTable()); 151 } 152 153 TEST_F(CodeTableTest, BadOpcode) { 154 VerifyInstruction(/* opcode */ 0, VCD_RUN, /* size */ 0, /* mode */ 0); 155 code_table_data_.inst1[0] = VCD_LAST_INSTRUCTION_TYPE + 1; 156 EXPECT_FALSE(ValidateCodeTable()); 157 code_table_data_.inst1[0] = 0xFF; 158 EXPECT_FALSE(ValidateCodeTable()); 159 } 160 161 TEST_F(CodeTableTest, BadMode) { 162 VerifyInstruction(/* opcode */ 131, VCD_COPY, /* size */ 0, /* mode */ 7); 163 code_table_data_.mode1[131] = VCDiffAddressCache::DefaultLastMode() + 1; 164 EXPECT_FALSE(ValidateCodeTable()); 165 code_table_data_.mode1[131] = 0xFF; 166 EXPECT_FALSE(ValidateCodeTable()); 167 } 168 169 TEST_F(CodeTableTest, AddWithNonzeroMode) { 170 VerifyInstruction(/* opcode */ 1, VCD_ADD, /* size */ 0, /* mode */ 0); 171 code_table_data_.mode1[1] = 1; 172 EXPECT_FALSE(ValidateCodeTable()); 173 } 174 175 TEST_F(CodeTableTest, RunWithNonzeroMode) { 176 VerifyInstruction(/* opcode */ 0, VCD_RUN, /* size */ 0, /* mode */ 0); 177 code_table_data_.mode1[0] = 1; 178 EXPECT_FALSE(ValidateCodeTable()); 179 } 180 181 TEST_F(CodeTableTest, NoOpWithNonzeroMode) { 182 VerifyInstruction(/* opcode */ 20, VCD_COPY, /* size */ 4, /* mode */ 0); 183 code_table_data_.inst1[20] = VCD_NOOP; 184 code_table_data_.mode1[20] = 0; 185 code_table_data_.size1[20] = 0; 186 EXPECT_TRUE(ValidateCodeTable()); 187 code_table_data_.mode1[20] = 1; 188 EXPECT_FALSE(ValidateCodeTable()); 189 } 190 191 TEST_F(CodeTableTest, NoOpWithNonzeroSize) { 192 VerifyInstruction(/* opcode */ 20, VCD_COPY, /* size */ 4, /* mode */ 0); 193 code_table_data_.inst1[20] = VCD_NOOP; 194 code_table_data_.mode1[20] = 0; 195 code_table_data_.size1[20] = 0; 196 EXPECT_TRUE(ValidateCodeTable()); 197 code_table_data_.size1[20] = 1; 198 EXPECT_FALSE(ValidateCodeTable()); 199 } 200 201 TEST_F(CodeTableTest, BadSecondOpcode) { 202 VerifyInstruction(/* opcode */ 20, VCD_COPY, /* size */ 4, /* mode */ 0); 203 code_table_data_.inst2[20] = VCD_LAST_INSTRUCTION_TYPE + 1; 204 EXPECT_FALSE(ValidateCodeTable()); 205 code_table_data_.inst2[20] = 0xFF; 206 EXPECT_FALSE(ValidateCodeTable()); 207 } 208 209 TEST_F(CodeTableTest, BadSecondMode) { 210 VerifyInstruction(/* opcode */ 20, VCD_COPY, /* size */ 4, /* mode */ 0); 211 code_table_data_.inst2[20] = VCD_COPY; 212 EXPECT_TRUE(ValidateCodeTable()); 213 code_table_data_.mode2[20] = VCDiffAddressCache::DefaultLastMode() + 1; 214 EXPECT_FALSE(ValidateCodeTable()); 215 code_table_data_.mode2[20] = 0xFF; 216 EXPECT_FALSE(ValidateCodeTable()); 217 } 218 219 TEST_F(CodeTableTest, AddSecondWithNonzeroMode) { 220 VerifyInstruction(/* opcode */ 20, VCD_COPY, /* size */ 4, /* mode */ 0); 221 code_table_data_.inst2[20] = VCD_ADD; 222 EXPECT_TRUE(ValidateCodeTable()); 223 code_table_data_.mode2[20] = 1; 224 EXPECT_FALSE(ValidateCodeTable()); 225 } 226 227 TEST_F(CodeTableTest, RunSecondWithNonzeroMode) { 228 VerifyInstruction(/* opcode */ 20, VCD_COPY, /* size */ 4, /* mode */ 0); 229 code_table_data_.inst2[20] = VCD_RUN; 230 EXPECT_TRUE(ValidateCodeTable()); 231 code_table_data_.mode2[20] = 1; 232 EXPECT_FALSE(ValidateCodeTable()); 233 } 234 235 TEST_F(CodeTableTest, SecondNoOpWithNonzeroMode) { 236 VerifyInstruction(/* opcode */ 20, VCD_COPY, /* size */ 4, /* mode */ 0); 237 EXPECT_EQ(VCD_NOOP, code_table_data_.inst2[20]); 238 code_table_data_.mode2[20] = 1; 239 EXPECT_FALSE(ValidateCodeTable()); 240 } 241 242 TEST_F(CodeTableTest, SecondNoOpWithNonzeroSize) { 243 VerifyInstruction(/* opcode */ 20, VCD_COPY, /* size */ 4, /* mode */ 0); 244 EXPECT_EQ(VCD_NOOP, code_table_data_.inst2[20]); 245 code_table_data_.size2[20] = 1; 246 EXPECT_FALSE(ValidateCodeTable()); 247 } 248 249 TEST_F(CodeTableTest, ValidateExerciseCodeTable) { 250 EXPECT_TRUE(g_exercise_code_table_->Validate(kLastExerciseMode)); 251 } 252 253 } // unnamed namespace 254 } // namespace open_vcdiff 255