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 //
18 // Run gtest tests from a JNI entry point.
19 
20 #include "gtest/gtest.h"
21 
22 #include <jni.h>
23 
24 #include <stdio.h>
25 
26 #include <algorithm>
27 #include <iterator>
28 #include <string>
29 #include <vector>
30 
31 #include "jni_test_main.h"
32 
33 namespace ndk_test {
34 
35 namespace {
36 
JStringToString(JNIEnv * env,jstring str)37 std::string JStringToString(JNIEnv* env, jstring str) {
38   jboolean is_copy;
39   const char* buffer = env->GetStringUTFChars(str, &is_copy);
40   std::string result(buffer);
41 
42   // Release the buffer always (regardless of |is_copy|).
43   // cf) http://developer.android.com/training/articles/perf-jni.html
44   env->ReleaseStringUTFChars(str, buffer);
45 
46   return result;
47 }
48 
PrintTestList(const std::vector<std::string> & test_list)49 void PrintTestList(const std::vector<std::string>& test_list) {
50   for (size_t i = 0; i < test_list.size(); ++i) {
51     fprintf(stderr, "%s%s", (i == 0) ? "" : ", ", test_list[i].c_str());
52   }
53 }
54 
55 // Verifies if all test cases are listed in |test_list|, and vice versa.
56 // If |test_list| is empty, the verification is skipped (i.e. always pass).
57 // On success, returns true, otherwise false and outputs the mismatch info
58 // to stderr.
VerifyTestList(const std::string & test_list)59 bool VerifyTestList(const std::string& test_list) {
60   // If the test_list is empty, we just skip the verification.
61   if (test_list.empty()) return true;
62 
63   // Split test_list by ':'.
64   std::vector<std::string> known_test_list;
65   {
66     size_t begin = 0;
67     while (true) {
68       size_t end = test_list.find(':', begin);
69       size_t len = (end == std::string::npos) ? std::string::npos : (end - begin);
70       known_test_list.push_back(test_list.substr(begin, len));
71       if (end == std::string::npos) break;
72       begin = end + 1;  // Skip ':'.
73     }
74   }
75   std::sort(known_test_list.begin(), known_test_list.end());
76 
77   // Traverse all TestInfo, and extract its names.
78   std::vector<std::string> actual_test_list;
79   ::testing::UnitTest* unit_test = ::testing::UnitTest::GetInstance();
80   for (int i = 0; i < unit_test->total_test_case_count(); ++i) {
81     const ::testing::TestCase* test_case = unit_test->GetTestCase(i);
82     for (int j = 0; j < test_case->total_test_count(); ++j) {
83       const ::testing::TestInfo* test_info = test_case->GetTestInfo(j);
84       actual_test_list.push_back(std::string(test_info->test_case_name()) + "." +
85                                  test_info->name());
86     }
87   }
88   std::sort(actual_test_list.begin(), actual_test_list.end());
89 
90   // Take the diff.
91   std::vector<std::string> missing_test_list;
92   std::set_difference(known_test_list.begin(),
93                       known_test_list.end(),
94                       actual_test_list.begin(),
95                       actual_test_list.end(),
96                       std::back_inserter(missing_test_list));
97   std::vector<std::string> unknown_test_list;
98   std::set_difference(actual_test_list.begin(),
99                       actual_test_list.end(),
100                       known_test_list.begin(),
101                       known_test_list.end(),
102                       std::back_inserter(unknown_test_list));
103 
104   if (missing_test_list.empty() && unknown_test_list.empty()) {
105     // Verification passes successfully.
106     return true;
107   }
108 
109   // Output mismatch info.
110   fprintf(stderr, "Mismatch test case is found.\n");
111   fprintf(stderr, "Expected test names: ");
112   PrintTestList(known_test_list);
113   fprintf(stderr, "\n");
114   fprintf(stderr, "Actual test names: ");
115   PrintTestList(actual_test_list);
116   fprintf(stderr, "\n");
117   if (!unknown_test_list.empty()) {
118     fprintf(stderr, "Unknown tests: ");
119     PrintTestList(unknown_test_list);
120     fprintf(stderr, "\n");
121   }
122   if (!missing_test_list.empty()) {
123     fprintf(stderr, "Missing tests: ");
124     PrintTestList(missing_test_list);
125     fprintf(stderr, "\n");
126   }
127   fprintf(stderr,
128           "Note: This mismatching happens maybe due to a new macro which is "
129           "expanded to TEST or TEST_F. Then, you may need to modify "
130           "extract_google_test_list.py script, which creates a full list "
131           "of test cases from the source code. However, please also think "
132           "about to use test expectations, instead.\n");
133 
134   return false;
135 }
136 
137 }  // namespace
138 
RunAllTests(JNIEnv * env,jobject,jstring gtest_list,jstring gtest_filter)139 int RunAllTests(JNIEnv* env, jobject /* thiz */, jstring gtest_list, jstring gtest_filter) {
140   int argc = 2;
141   const char* args[3];
142   args[0] = "";
143   args[1] = "--gtest_output=xml:/data/data/com.example.ndk_tests/cache/out.xml";
144 
145   std::string gtest_filter_arg;
146   if (env->GetStringUTFLength(gtest_filter) > 0) {
147     gtest_filter_arg = "--gtest_filter=" + JStringToString(env, gtest_filter);
148     args[2] = gtest_filter_arg.c_str();
149     ++argc;
150   }
151 
152   ::testing::InitGoogleTest(&argc, const_cast<char**>(args));
153   if (!VerifyTestList(JStringToString(env, gtest_list))) {
154     // On verification failure, return -1.
155     return -1;
156   }
157 
158   return RUN_ALL_TESTS();
159 }
160 
161 }  // namespace ndk_test
162