1 /*
2  * Copyright 2013 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 #define LOG_TAG "GLTest"
18 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
19 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
20 
21 #include <android/log.h>
22 #include <android/native_window.h>
23 #include <GLTestHelper.h>
24 
25 // this listener is used to forward the subset of
26 // gtest output needed to generate CTS results
27 class CTSGTestListener : public EmptyTestEventListener {
28 public:
CTSGTestListener(JNIEnv * env,jobject activity)29     CTSGTestListener(JNIEnv *env, jobject activity)
30         : mActivity(activity), mEnv(env) {
31 
32         jclass clazz = env->FindClass(
33               "android/test/wrappedgtest/WrappedGTestActivity");
34         mSendStatusID = env->GetMethodID(clazz, "sendStatus",
35               "(Ljava/lang/String;)V");
36         mMessageBuffer = new char[2048];
37     }
38 
~CTSGTestListener()39     ~CTSGTestListener() {
40         delete[] mMessageBuffer;
41     }
42 
43 private:
44     jobject   mActivity;
45     JNIEnv *  mEnv;
46     jmethodID mSendStatusID;
47     char *    mMessageBuffer;
48 
OnTestIterationStart(const UnitTest & unit_test,int iteration)49     virtual void OnTestIterationStart(const UnitTest& unit_test,
50             int iteration) {
51         snprintf(mMessageBuffer, sizeof(char) * 2048,
52                 "[==========] Running %i tests from %i test cases.",
53                 unit_test.test_to_run_count(),
54                 unit_test.test_case_to_run_count());
55 
56         mEnv->CallVoidMethod(mActivity, mSendStatusID,
57                 mEnv->NewStringUTF(mMessageBuffer));
58     }
59 
OnTestStart(const TestInfo & test_info)60     virtual void OnTestStart(const TestInfo& test_info) {
61         snprintf(mMessageBuffer, sizeof(char) * 2048, "[ RUN      ] %s.%s",
62                 test_info.test_case_name(), test_info.name());
63 
64         mEnv->CallVoidMethod(mActivity, mSendStatusID,
65                 mEnv->NewStringUTF(mMessageBuffer));
66     }
67 
OnTestPartResult(const TestPartResult & result)68     virtual void OnTestPartResult(const TestPartResult& result) {
69         if (result.type() == TestPartResult::kSuccess) {
70             return;
71         }
72 
73         snprintf(mMessageBuffer, sizeof(char) * 2048, "%s:%i: Failure\n%s",
74                 result.file_name(), result.line_number(), result.message());
75 
76         mEnv->CallVoidMethod(mActivity, mSendStatusID,
77                 mEnv->NewStringUTF(mMessageBuffer));
78     }
79 
OnTestEnd(const TestInfo & test_info)80     virtual void OnTestEnd(const TestInfo& test_info) {
81         const char * result = test_info.result()->Passed() ?
82                 "[       OK ] " : "[  FAILED  ] ";
83 
84         snprintf(mMessageBuffer, sizeof(char) * 2048, "%s%s.%s (%lli ms)",
85                 result, test_info.test_case_name(), test_info.name(),
86                 test_info.result()->elapsed_time());
87 
88         mEnv->CallVoidMethod(mActivity, mSendStatusID,
89                 mEnv->NewStringUTF(mMessageBuffer));
90     }
91 
OnTestIterationEnd(const UnitTest & unit_test,int iteration)92     virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) {
93         snprintf(mMessageBuffer, sizeof(char) * 2048,
94                 "[==========] %i tests from %i test cases ran. (%lli ms total)",
95                 unit_test.test_to_run_count(),
96                 unit_test.test_case_to_run_count(), unit_test.elapsed_time());
97 
98         mEnv->CallVoidMethod(mActivity, mSendStatusID,
99                 mEnv->NewStringUTF(mMessageBuffer));
100     }
101 };
102 
103 // this listener is similar to the default gtest listener
104 // but it outputs the results to the log instead of stdout
105 class LogGTestListener : public EmptyTestEventListener {
106 
107 private:
OnTestIterationStart(const UnitTest & unit_test,int iteration)108     virtual void OnTestIterationStart(const UnitTest& unit_test,
109             int iteration) {
110         LOGI("[==========] Running %i tests from %i test cases.\n",
111                 unit_test.test_to_run_count(),
112                 unit_test.test_case_to_run_count());
113     }
114 
OnEnvironmentsSetUpStart(const UnitTest & unit_test)115     virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) {
116         LOGI("[==========] Global test environment set-up.\n");
117     }
118 
OnTestCaseStart(const TestCase & test_case)119     virtual void OnTestCaseStart(const TestCase& test_case) {
120         LOGI("[----------] %i tests from %s\n",
121                 test_case.test_to_run_count(),
122                 test_case.name());
123 
124     }
125 
OnTestStart(const TestInfo & test_info)126     virtual void OnTestStart(const TestInfo& test_info) {
127         LOGI("[ RUN      ] %s.%s\n", test_info.test_case_name(),
128                 test_info.name());
129 
130     }
131 
OnTestPartResult(const TestPartResult & result)132     virtual void OnTestPartResult(const TestPartResult& result) {
133         if (result.type() == TestPartResult::kSuccess) {
134             return;
135         }
136 
137         LOGI("%s:%i: Failure\n%s\n", result.file_name(), result.line_number(),
138                 result.message());
139     }
140 
OnTestEnd(const TestInfo & test_info)141     virtual void OnTestEnd(const TestInfo& test_info) {
142         const char * result = test_info.result()->Passed() ?
143                 "[       OK ] " : "[  FAILED  ] ";
144 
145         LOGI("%s%s.%s (%lli ms)\n", result, test_info.test_case_name(),
146                 test_info.name(), test_info.result()->elapsed_time());
147     }
148 
149 
OnTestCaseEnd(const TestCase & test_case)150     virtual void OnTestCaseEnd(const TestCase& test_case) {
151         LOGI("[----------] %i tests from %s (%lli ms total)\n",
152                 test_case.test_to_run_count(), test_case.name(),
153                 test_case.elapsed_time());
154 
155     }
156 
OnEnvironmentsTearDownStart(const UnitTest & unit_test)157     virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) {
158         LOGI("[==========] Global test environment tear-down.\n");
159     }
160 
PrintFailedTests(const UnitTest & unit_test)161     void PrintFailedTests(const UnitTest& unit_test) {
162         const int failed_test_count = unit_test.failed_test_count();
163         if (failed_test_count == 0) {
164             return;
165         }
166 
167         for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
168             const TestCase& test_case = *unit_test.GetTestCase(i);
169 
170             if (!test_case.should_run() || test_case.failed_test_count() == 0) {
171                 continue;
172             }
173 
174             for (int j = 0; j < test_case.total_test_count(); ++j) {
175                 const TestInfo& test_info = *test_case.GetTestInfo(j);
176                 if (!test_info.should_run() || test_info.result()->Passed()) {
177                     continue;
178                 }
179                 LOGI("[  FAILED  ] %s.%s\n", test_case.name(),
180                         test_info.name());
181             }
182         }
183     }
OnTestIterationEnd(const UnitTest & unit_test,int iteration)184     virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) {
185         LOGI("[==========] %i tests from %i test cases ran. (%lli ms total)\n",
186                 unit_test.test_to_run_count(),
187                 unit_test.test_case_to_run_count(), unit_test.elapsed_time());
188 
189         LOGI("[  PASSED  ] %i tests\n", unit_test.successful_test_count());
190 
191         if(unit_test.Passed()) {
192             return;
193         }
194 
195         LOGI("[  FAILED  ] %i tests, listed below:\n",
196                 unit_test.failed_test_count());
197 
198         PrintFailedTests(unit_test);
199 
200         LOGI("\n%2d FAILED TESTS\n", unit_test.failed_test_count());
201     }
202 };
203 
204 ANativeWindow* GLTestHelper::mWindow;
205 
getWindow()206 ANativeWindow* GLTestHelper::getWindow() {
207     return mWindow;
208 }
209 
setWindow(JNIEnv * env,jobject obj,jobject surface)210 void GLTestHelper::setWindow(JNIEnv *env, jobject obj, jobject surface) {
211     mWindow = ANativeWindow_fromSurface(env, surface);
212 }
213 
runGTests(TestEventListener * listener,char * filter)214 int GLTestHelper::runGTests(TestEventListener * listener, char * filter) {
215 
216     if (filter) {
217         ::testing::GTEST_FLAG(filter) = filter;
218     }
219 
220     int argc = 0;
221     InitGoogleTest(&argc, (char**)NULL);
222 
223     TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
224     delete listeners.Release(listeners.default_result_printer());
225 
226     listeners.Append(listener);
227     int result = RUN_ALL_TESTS();
228     return result;
229 }
230 
runTests(JNIEnv * env,jobject obj,jstring filter)231 int GLTestHelper::runTests(JNIEnv *env, jobject obj, jstring filter) {
232     LogGTestListener * listener = new LogGTestListener();
233 
234     char * filter_cstr = NULL;
235 
236     // set filter if there is one
237     if (filter) {
238        filter_cstr = new char[512];
239        const char * ptr = env->GetStringUTFChars(filter, NULL);
240        snprintf(filter_cstr, sizeof(char) * 512, "%s", ptr);
241        env->ReleaseStringUTFChars(filter, ptr);
242     }
243 
244     int result = runGTests(listener, filter_cstr);
245 
246     if (filter_cstr) {
247         delete[] filter_cstr;
248     }
249 
250     delete listener;
251     return result;
252 }
253 
runTestsCTS(JNIEnv * env,jobject obj,jobject activity)254 int GLTestHelper::runTestsCTS(JNIEnv *env, jobject obj, jobject activity) {
255     CTSGTestListener * listener = new CTSGTestListener(env, activity);
256     int result = runGTests(listener, NULL);
257     delete listener;
258     return result;
259 }
260 
registerNative(JNIEnv * env)261 int GLTestHelper::registerNative(JNIEnv * env) {
262 
263     jclass clazz = env->FindClass("com/android/opengl/cts/GLTestActivity");
264 
265     jthrowable exception = env->ExceptionOccurred();
266     // CTS class not found, assume stand-alone application
267     if (exception) {
268         env->ExceptionClear();
269 
270         if (!env->IsInstanceOf(env->ExceptionOccurred(),
271                     env->FindClass("java/lang/NoClassDefFoundError"))) {
272             env->Throw(exception);
273         }
274 
275         //
276         JNINativeMethod standaloneMethods[] = {
277             // name, signature, function
278             { "setSurface", "(Landroid/view/Surface;)V", (void*)(GLTestHelper::setWindow) },
279             { "runTests", "(Ljava/lang/String;)V", (void*)(GLTestHelper::runTests) },
280         };
281 
282         return env->RegisterNatives(
283                 env->FindClass("com/android/gltest/GLTestActivity"),
284                 standaloneMethods,
285                 sizeof(standaloneMethods) / sizeof(JNINativeMethod));
286     }
287 
288     // GLTestActivity methods
289     JNINativeMethod glTestActMethods[] = {
290         // name, signature, function
291         { "setSurface", "(Landroid/view/Surface;)V", (void*)(GLTestHelper::setWindow) },
292     };
293 
294     int result = env->RegisterNatives(clazz, glTestActMethods,
295                          sizeof(glTestActMethods) / sizeof(JNINativeMethod));
296 
297     if (result) {
298         return result;
299     }
300 
301     // WrappedGTestActivity methods
302     JNINativeMethod wrappedGTestActMethods[] = {
303         // name, signature, function
304         { "runTests", "(Landroid/test/wrappedgtest/WrappedGTestActivity;)I",
305             (void*)(GLTestHelper::runTestsCTS) },
306     };
307 
308     return env->RegisterNatives(
309             env->FindClass("android/test/wrappedgtest/WrappedGTestActivity"),
310             wrappedGTestActMethods,
311             sizeof(wrappedGTestActMethods) / sizeof(JNINativeMethod));
312 }
313