JniClassTest.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /*
  2. * Author: Patrick-Christopher Mattulat
  3. * Co-Author: Claude Sonnet 4.6 (LLM)
  4. * Company: Lynar Studios
  5. * E-Mail: webmaster@lynarstudios.com
  6. * Created: 2023-04-07
  7. * Changed: 2026-06-23
  8. *
  9. * */
  10. #include <gmock/gmock.h>
  11. #include <gtest/gtest.h>
  12. #include <ls-std-core-jni-test.hpp>
  13. #include <ls-std/ls-std-core-jni.hpp>
  14. #include <ls-std/ls-std-core.hpp>
  15. #include <memory>
  16. using ls::standard::core::IllegalArgumentException;
  17. using ls::standard::core::NullPointerException;
  18. using ls::standard::core::experimental::JniClass;
  19. using ls::standard::core::experimental::JniClassParameter;
  20. using std::make_shared;
  21. using std::shared_ptr;
  22. using std::string;
  23. using test::core::jni::MockJniApi;
  24. using testing::AtLeast;
  25. using testing::Return;
  26. using testing::Test;
  27. namespace
  28. {
  29. class JniClassTest : public Test
  30. {
  31. public:
  32. JniClassTest() = default;
  33. ~JniClassTest() override = default;
  34. JniClass createJniClass(const string &_classPath)
  35. {
  36. auto parameter = make_shared<JniClassParameter>();
  37. this->jniApi = make_shared<MockJniApi>();
  38. parameter->setJniApi(this->jniApi);
  39. auto environment = make_shared<JNIEnv>();
  40. parameter->setJavaEnvironment(environment.get());
  41. return JniClass{parameter, _classPath};
  42. }
  43. shared_ptr<MockJniApi> jniApi{};
  44. };
  45. TEST_F(JniClassTest, constructor_no_parameter_reference)
  46. {
  47. EXPECT_THROW(
  48. {
  49. try
  50. {
  51. JniClass javaClass(nullptr, "java.utils.String");
  52. }
  53. catch (const IllegalArgumentException &_exception)
  54. {
  55. string expected = _exception.getName() + " thrown - no provided reference to JNI class parameter!";
  56. string actual = _exception.what();
  57. ASSERT_STREQ(expected.c_str(), actual.c_str());
  58. throw;
  59. }
  60. },
  61. IllegalArgumentException);
  62. }
  63. TEST_F(JniClassTest, constructor_empty_path)
  64. {
  65. EXPECT_THROW(
  66. {
  67. try
  68. {
  69. JniClass javaClass(make_shared<JniClassParameter>(), "");
  70. }
  71. catch (const IllegalArgumentException &_exception)
  72. {
  73. string expected = _exception.getName() + " thrown - path to associated Java class is empty!";
  74. string actual = _exception.what();
  75. ASSERT_STREQ(expected.c_str(), actual.c_str());
  76. throw;
  77. }
  78. },
  79. IllegalArgumentException);
  80. }
  81. TEST_F(JniClassTest, constructor_no_java_environment_reference)
  82. {
  83. EXPECT_THROW(
  84. {
  85. try
  86. {
  87. JniClass javaClass(make_shared<JniClassParameter>(), "java.utils.String");
  88. }
  89. catch (const IllegalArgumentException &_exception)
  90. {
  91. string expected = _exception.getName() + " thrown - Java environment is not being provided!";
  92. string actual = _exception.what();
  93. ASSERT_STREQ(expected.c_str(), actual.c_str());
  94. throw;
  95. }
  96. },
  97. IllegalArgumentException);
  98. }
  99. TEST_F(JniClassTest, callMethod_boolean_return_value)
  100. {
  101. string classPath = "java.utils.String";
  102. JniClass javaClass = this->createJniClass(classPath);
  103. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  104. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  105. string methodIdentifier = "isBlue";
  106. string methodSignature = "()Z";
  107. EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
  108. auto methodId = (jmethodID) make_shared<int>().get();
  109. ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
  110. EXPECT_CALL(*this->jniApi, callBooleanMethod(testing::_, methodId)).Times(AtLeast(1));
  111. ON_CALL(*this->jniApi, callBooleanMethod(testing::_, methodId)).WillByDefault(Return(true));
  112. ASSERT_TRUE(javaClass.load());
  113. ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
  114. ASSERT_TRUE(javaClass.callMethod(methodIdentifier).getBooleanValue());
  115. }
  116. TEST_F(JniClassTest, callMethod_byte_return_value)
  117. {
  118. string classPath = "java.utils.String";
  119. JniClass javaClass = this->createJniClass(classPath);
  120. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  121. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  122. string methodIdentifier = "getDay";
  123. string methodSignature = "()B";
  124. EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
  125. auto methodId = (jmethodID) make_shared<int>().get();
  126. ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
  127. EXPECT_CALL(*this->jniApi, callByteMethod(testing::_, methodId)).Times(AtLeast(1));
  128. ON_CALL(*this->jniApi, callByteMethod(testing::_, methodId)).WillByDefault(Return(22));
  129. ASSERT_TRUE(javaClass.load());
  130. ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
  131. ASSERT_EQ(22, javaClass.callMethod(methodIdentifier).getByteValue());
  132. }
  133. TEST_F(JniClassTest, callMethod_char_return_value)
  134. {
  135. string classPath = "java.utils.String";
  136. JniClass javaClass = this->createJniClass(classPath);
  137. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  138. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  139. string methodIdentifier = "getLetter";
  140. string methodSignature = "()C";
  141. EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
  142. auto methodId = (jmethodID) make_shared<int>().get();
  143. ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
  144. EXPECT_CALL(*this->jniApi, callCharMethod(testing::_, methodId)).Times(AtLeast(1));
  145. ON_CALL(*this->jniApi, callCharMethod(testing::_, methodId)).WillByDefault(Return('P'));
  146. ASSERT_TRUE(javaClass.load());
  147. ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
  148. ASSERT_EQ('P', javaClass.callMethod(methodIdentifier).getCharValue());
  149. }
  150. TEST_F(JniClassTest, callMethod_double_return_value)
  151. {
  152. string classPath = "java.utils.String";
  153. JniClass javaClass = this->createJniClass(classPath);
  154. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  155. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  156. string methodIdentifier = "getPi";
  157. string methodSignature = "()D";
  158. EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
  159. auto methodId = (jmethodID) make_shared<int>().get();
  160. ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
  161. EXPECT_CALL(*this->jniApi, callDoubleMethod(testing::_, methodId)).Times(AtLeast(1));
  162. ON_CALL(*this->jniApi, callDoubleMethod(testing::_, methodId)).WillByDefault(Return(3.14159265L));
  163. ASSERT_TRUE(javaClass.load());
  164. ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
  165. ASSERT_DOUBLE_EQ(3.14159265l, javaClass.callMethod(methodIdentifier).getDoubleValue());
  166. }
  167. TEST_F(JniClassTest, callMethod_float_return_value)
  168. {
  169. string classPath = "java.utils.String";
  170. JniClass javaClass = this->createJniClass(classPath);
  171. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  172. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  173. string methodIdentifier = "getPi";
  174. string methodSignature = "()F";
  175. EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
  176. auto methodId = (jmethodID) make_shared<int>().get();
  177. ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
  178. EXPECT_CALL(*this->jniApi, callFloatMethod(testing::_, methodId)).Times(AtLeast(1));
  179. ON_CALL(*this->jniApi, callFloatMethod(testing::_, methodId)).WillByDefault(Return(3.14159F));
  180. ASSERT_TRUE(javaClass.load());
  181. ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
  182. ASSERT_FLOAT_EQ(3.14159f, javaClass.callMethod(methodIdentifier).getFloatValue());
  183. }
  184. TEST_F(JniClassTest, callMethod_integer_return_value)
  185. {
  186. string classPath = "java.utils.String";
  187. JniClass javaClass = this->createJniClass(classPath);
  188. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  189. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  190. string methodIdentifier = "getYear";
  191. string methodSignature = "()I";
  192. EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
  193. auto methodId = (jmethodID) make_shared<int>().get();
  194. ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
  195. EXPECT_CALL(*this->jniApi, callIntMethod(testing::_, methodId)).Times(AtLeast(1));
  196. ON_CALL(*this->jniApi, callIntMethod(testing::_, methodId)).WillByDefault(Return(1989));
  197. ASSERT_TRUE(javaClass.load());
  198. ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
  199. ASSERT_EQ(1989, javaClass.callMethod(methodIdentifier).getIntegerValue());
  200. }
  201. TEST_F(JniClassTest, callMethod_long_return_value)
  202. {
  203. string classPath = "java.utils.String";
  204. JniClass javaClass = this->createJniClass(classPath);
  205. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  206. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  207. string methodIdentifier = "getAmountOfMoney";
  208. string methodSignature = "()J";
  209. EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
  210. auto methodId = (jmethodID) make_shared<int>().get();
  211. ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
  212. EXPECT_CALL(*this->jniApi, callLongMethod(testing::_, methodId)).Times(AtLeast(1));
  213. ON_CALL(*this->jniApi, callLongMethod(testing::_, methodId)).WillByDefault(Return(18837828981));
  214. ASSERT_TRUE(javaClass.load());
  215. ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
  216. ASSERT_EQ(18837828981, javaClass.callMethod(methodIdentifier).getLongValue());
  217. }
  218. TEST_F(JniClassTest, callMethod_short_return_value)
  219. {
  220. string classPath = "java.utils.String";
  221. JniClass javaClass = this->createJniClass(classPath);
  222. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  223. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  224. string methodIdentifier = "getDay";
  225. string methodSignature = "()S";
  226. EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
  227. auto methodId = (jmethodID) make_shared<int>().get();
  228. ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
  229. EXPECT_CALL(*this->jniApi, callShortMethod(testing::_, methodId)).Times(AtLeast(1));
  230. ON_CALL(*this->jniApi, callShortMethod(testing::_, methodId)).WillByDefault(Return(55));
  231. ASSERT_TRUE(javaClass.load());
  232. ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
  233. ASSERT_EQ(55, javaClass.callMethod(methodIdentifier).getShortValue());
  234. }
  235. TEST_F(JniClassTest, hasMethod)
  236. {
  237. string classPath = "java.utils.String";
  238. JniClass javaClass = this->createJniClass(classPath);
  239. ASSERT_FALSE(javaClass.hasMethod("getDay"));
  240. }
  241. TEST_F(JniClassTest, load)
  242. {
  243. string classPath = "java.utils.String";
  244. JniClass javaClass = this->createJniClass(classPath);
  245. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  246. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  247. ASSERT_TRUE(javaClass.load());
  248. }
  249. TEST_F(JniClassTest, loadMethod)
  250. {
  251. string classPath = "java.utils.String";
  252. JniClass javaClass = this->createJniClass(classPath);
  253. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  254. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  255. string methodIdentifier = "getDay";
  256. string methodSignature = "()B";
  257. EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
  258. auto methodId = (jmethodID) make_shared<int>().get();
  259. ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
  260. ASSERT_TRUE(javaClass.load());
  261. ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
  262. }
  263. TEST_F(JniClassTest, loadMethod_repeat)
  264. {
  265. string classPath = "java.utils.String";
  266. JniClass javaClass = this->createJniClass(classPath);
  267. EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
  268. ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
  269. string methodIdentifier = "getDay";
  270. string methodSignature = "()B";
  271. EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
  272. auto methodId = (jmethodID) make_shared<int>().get();
  273. ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
  274. ASSERT_TRUE(javaClass.load());
  275. ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
  276. ASSERT_FALSE(javaClass.loadMethod(methodIdentifier, methodSignature));
  277. }
  278. TEST_F(JniClassTest, loadMethod_without_previous_class_load)
  279. {
  280. string classPath = "java.utils.String";
  281. JniClass javaClass = this->createJniClass(classPath);
  282. string methodIdentifier = "getDay";
  283. string methodSignature = "()B";
  284. EXPECT_THROW(
  285. {
  286. try
  287. {
  288. javaClass.loadMethod(methodIdentifier, methodSignature);
  289. }
  290. catch (const NullPointerException &_exception)
  291. {
  292. string expected = _exception.getName() + " thrown - no Java class reference available for loading class method!";
  293. string actual = _exception.what();
  294. ASSERT_STREQ(expected.c_str(), actual.c_str());
  295. throw;
  296. }
  297. },
  298. NullPointerException);
  299. }
  300. }