Home | History | Annotate | Download | only in src
      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