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 
CanonicalNameToPath(const char * package_class,const char * extension)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 
SplitPackageClass(const string & package_class,string * rel_path,string * package,string * class_name)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 
PrintDiff(const string & a,const string & b)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