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