Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 2015, The Android Open Source Project
      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 
     17 #include <algorithm>
     18 #include <iostream>
     19 #include <iterator>
     20 
     21 #include <android-base/strings.h>
     22 
     23 #include "os.h"
     24 #include "tests/test_util.h"
     25 
     26 using android::base::Split;
     27 using android::base::Join;
     28 using std::string;
     29 using std::vector;
     30 using std::cout;
     31 using std::endl;
     32 using std::distance;
     33 
     34 namespace android {
     35 namespace aidl {
     36 namespace test {
     37 
     38 string CanonicalNameToPath(const char* package_class, const char* extension) {
     39   string rel_path{package_class};
     40   for (char& c : rel_path) {
     41     if (c == '.') {
     42       c = OS_PATH_SEPARATOR;
     43     }
     44   }
     45   rel_path += extension;
     46   return rel_path;
     47 }
     48 
     49 void SplitPackageClass(const string& package_class,
     50                        string* rel_path,
     51                        string* package,
     52                        string* class_name) {
     53   *package = string{package_class, 0, package_class.rfind('.')};
     54   *class_name = string{package_class, package_class.rfind('.') + 1};
     55   *rel_path = CanonicalNameToPath(package_class.c_str(), ".aidl");
     56 }
     57 
     58 void PrintDiff(const string& a, const string& b) {
     59   const int LEFT = 1;
     60   const int UP = 2;
     61   const int UP_LEFT = 4;
     62 
     63   auto a_lines = Split(a, "\n");
     64   auto b_lines = Split(b, "\n");
     65 
     66   struct diff_table_entry {
     67     size_t longest_common_subsequence_length;
     68     int propagation_directions;
     69   };
     70 
     71   diff_table_entry table[a_lines.size() + 1][b_lines.size() + 1];
     72 
     73   for (size_t i = 0; i < a_lines.size() + 1; ++i) {
     74     for (size_t j = 0; j < b_lines.size() + 1; ++j) {
     75       if (i == 0 || j == 0) {
     76         int directions = 0;
     77 
     78         if (i) {
     79           directions |= UP;
     80         }
     81 
     82         if (j) {
     83           directions |= LEFT;
     84         }
     85 
     86         table[i][j].longest_common_subsequence_length = 0;
     87         table[i][j].propagation_directions = directions;
     88       } else if (a_lines[i-1] == b_lines[j-1]) {
     89         table[i][j].longest_common_subsequence_length =
     90             table[i-1][j-1].longest_common_subsequence_length + 1;
     91         table[i][j].propagation_directions = UP_LEFT;
     92       } else {
     93         size_t length_up = table[i-1][j].longest_common_subsequence_length;
     94         size_t length_left = table[i][j-1].longest_common_subsequence_length;
     95         int directions = 0;
     96         size_t length;
     97 
     98         if (length_up >= length_left) {
     99           directions |= UP;
    100           length = length_up;
    101         }
    102 
    103         if (length_left >= length_up) {
    104           directions |= LEFT;
    105           length = length_left;
    106         }
    107 
    108         table[i][j].longest_common_subsequence_length = length;
    109         table[i][j].propagation_directions = directions;
    110       }
    111     }
    112   }
    113 
    114   size_t i = a_lines.size();
    115   size_t j = b_lines.size();
    116   vector<string> output;
    117 
    118   while (table[i][j].propagation_directions) {
    119     if (table[i][j].propagation_directions & UP_LEFT) {
    120       output.push_back(" " + a_lines[i-1]);
    121       i--;
    122       j--;
    123     } else if (table[i][j].propagation_directions & UP) {
    124       output.push_back("-" + a_lines[i-1]);
    125       i--;
    126     } else {
    127       output.push_back("+" + b_lines[j-1]);
    128       j--;
    129     }
    130   }
    131 
    132   int print_mask = 0;
    133   bool printed_last = false;
    134   size_t line_number = 0;
    135 
    136   for (auto it = output.crbegin(), frontier = output.crbegin();
    137        it != output.crend(); ++it) {
    138     while (frontier != output.crend() && distance(it, frontier) <= 3) {
    139       print_mask <<= 1;
    140       print_mask &= 0x7f;
    141 
    142       if ((*frontier)[0] != ' ') {
    143         print_mask |= 1;
    144       }
    145 
    146       frontier++;
    147     }
    148 
    149     if ((*it)[0] != '-') {
    150       line_number++;
    151     }
    152 
    153     if (print_mask) {
    154       if (!printed_last) {
    155         cout << "Line: " << line_number << endl;
    156       }
    157 
    158       cout << *it << endl;
    159       printed_last = true;
    160     } else {
    161       printed_last = false;
    162     }
    163   }
    164 }
    165 
    166 }  // namespace test
    167 }  // namespace android
    168 }  // namespace aidl
    169