• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CodeTableTest()28   CodeTableTest()
29   : code_table_data_(VCDiffCodeTableData::kDefaultCodeTableData) { }
30 
~CodeTableTest()31   virtual ~CodeTableTest() { }
32 
SetUp()33   virtual void SetUp() {
34     // Default code table must pass
35     EXPECT_TRUE(ValidateCodeTable());
36   }
37 
AddExerciseOpcode(unsigned char inst1,unsigned char mode1,unsigned char size1,unsigned char inst2,unsigned char mode2,unsigned char size2,int opcode)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 
SetUpTestCase()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 
TearDownTestCase()88   static void TearDownTestCase() {
89     delete g_exercise_code_table_;
90   }
91 
VerifyInstruction(unsigned char opcode,unsigned char inst,unsigned char size,unsigned char mode)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 
ValidateCodeTable()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.
TEST_F(CodeTableTest,MissingCopyMode)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 
TEST_F(CodeTableTest,MissingAdd)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 
TEST_F(CodeTableTest,MissingRun)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 
TEST_F(CodeTableTest,BadOpcode)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 
TEST_F(CodeTableTest,BadMode)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 
TEST_F(CodeTableTest,AddWithNonzeroMode)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 
TEST_F(CodeTableTest,RunWithNonzeroMode)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 
TEST_F(CodeTableTest,NoOpWithNonzeroMode)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 
TEST_F(CodeTableTest,NoOpWithNonzeroSize)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 
TEST_F(CodeTableTest,BadSecondOpcode)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 
TEST_F(CodeTableTest,BadSecondMode)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 
TEST_F(CodeTableTest,AddSecondWithNonzeroMode)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 
TEST_F(CodeTableTest,RunSecondWithNonzeroMode)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 
TEST_F(CodeTableTest,SecondNoOpWithNonzeroMode)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 
TEST_F(CodeTableTest,SecondNoOpWithNonzeroSize)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 
TEST_F(CodeTableTest,ValidateExerciseCodeTable)249 TEST_F(CodeTableTest, ValidateExerciseCodeTable) {
250   EXPECT_TRUE(g_exercise_code_table_->Validate(kLastExerciseMode));
251 }
252 
253 }  // unnamed namespace
254 }  // namespace open_vcdiff
255