1 /*
2  * Copyright (C) 2019 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 <string>
18 
19 #include <android-base/test_utils.h>
20 #include <gtest/gtest.h>
21 
22 #include "ApiChecker.h"
23 #include "Common.h"
24 
25 namespace {
26 
27 constexpr const char* kLatestApi =
28     R"(
29 props {
30     owner: Platform
31     module: "android.all_dep"
32     prop {
33         api_name: "dep1"
34         type: Integer
35         scope: Public
36         access: ReadWrite
37         prop_name: "dep1_int"
38         deprecated: true
39     }
40 }
41 props {
42     owner: Platform
43     module: "android.legacy"
44     prop {
45         api_name: "legacy_prop"
46         type: String
47         scope: Public
48         access: Readonly
49         prop_name: "legacy_prop"
50     }
51 }
52 props {
53     owner: Platform
54     module: "android.platprop"
55     prop {
56         api_name: "prop1"
57         type: Long
58         scope: Public
59         access: ReadWrite
60         prop_name: "prop1"
61     }
62     prop {
63         api_name: "prop3"
64         type: Boolean
65         scope: Public
66         access: ReadWrite
67         prop_name: "ctl.start$prop3"
68     }
69     prop {
70         api_name: "prop4"
71         type: String
72         scope: Public
73         access: Readonly
74         prop_name: "ro.prop4"
75     }
76 }
77 )";
78 
79 constexpr const char* kCurrentApi =
80     R"(
81 props {
82     owner: Platform
83     module: "android.legacy"
84     prop {
85         api_name: "new_prop"
86         type: String
87         scope: Public
88         access: Readonly
89         prop_name: "new_prop"
90         legacy_prop_name: "legacy_prop"
91     }
92 }
93 props {
94     owner: Platform
95     module: "android.platprop"
96     prop {
97         api_name: "prop1"
98         type: Long
99         scope: Public
100         access: ReadWrite
101         prop_name: "prop1"
102     }
103     prop {
104         api_name: "prop2"
105         type: Integer
106         scope: Public
107         access: Writeonce
108         prop_name: "ro.public.prop2"
109     }
110     prop {
111         api_name: "prop3"
112         type: Boolean
113         scope: Public
114         access: ReadWrite
115         prop_name: "ctl.start$prop3"
116     }
117     prop {
118         api_name: "prop4"
119         type: String
120         scope: Public
121         access: Readonly
122         prop_name: "ro.prop4"
123         deprecated: true
124     }
125 
126 }
127 )";
128 
129 constexpr const char* kInvalidCurrentApi =
130     R"(
131 props {
132     owner: Platform
133     module: "android.legacy"
134     prop {
135         api_name: "legacy_prop"
136         type: String
137         scope: Public
138         access: Readonly
139         prop_name: "legacy_prop"
140     }
141 }
142 props {
143     prop {
144         api_name: "prop1"
145         type: Integer
146         scope: Public
147         access: Readonly
148         prop_name: "prop1"
149     }
150     owner: Platform
151     module: "android.platprop"
152     prop {
153         api_name: "prop3"
154         type: Boolean
155         scope: Public
156         access: ReadWrite
157         integer_as_bool: true
158         prop_name: "ctl.start$prop3"
159     }
160 }
161 )";
162 
163 }  // namespace
164 
TEST(SyspropTest,ApiCheckerTest)165 TEST(SyspropTest, ApiCheckerTest) {
166   TemporaryFile latest_file;
167   close(latest_file.fd);
168   latest_file.fd = -1;
169   ASSERT_TRUE(android::base::WriteStringToFile(kLatestApi, latest_file.path));
170 
171   std::string err;
172   auto latest_api = ParseApiFile(latest_file.path);
173   ASSERT_RESULT_OK(latest_api);
174 
175   TemporaryFile current_file;
176   close(current_file.fd);
177   current_file.fd = -1;
178   ASSERT_TRUE(android::base::WriteStringToFile(kCurrentApi, current_file.path));
179 
180   auto current_api = ParseApiFile(current_file.path);
181   ASSERT_RESULT_OK(current_api);
182   EXPECT_RESULT_OK(CompareApis(*latest_api, *current_api));
183 
184   TemporaryFile invalid_current_file;
185   close(invalid_current_file.fd);
186   invalid_current_file.fd = -1;
187   ASSERT_TRUE(android::base::WriteStringToFile(kInvalidCurrentApi,
188                                                invalid_current_file.path));
189 
190   auto invalid_current_api = ParseApiFile(invalid_current_file.path);
191   ASSERT_RESULT_OK(invalid_current_api);
192 
193   auto res = CompareApis(*latest_api, *invalid_current_api);
194   EXPECT_FALSE(res.ok());
195 
196   EXPECT_EQ(res.error().message(),
197             "Type of prop prop1 has been changed\n"
198             "Accessibility of prop prop1 has become more restrictive\n"
199             "Integer-as-bool of prop prop3 has been changed\n"
200             "Prop prop4 has been removed\n");
201 }
202