You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

183 rivejä
5.2 KiB

  1. #pragma once
  2. #include <string>
  3. #include <gtest/gtest.h>
  4. #include <gmock/gmock.h>
  5. #include "mariadb_mock.h"
  6. ACTION(EscapeString)
  7. {
  8. char* dst = arg0;
  9. const char* src = arg1;
  10. unsigned long len = arg2;
  11. if (len <= 0)
  12. return 0;
  13. *(dst++) = 'X';
  14. for (unsigned long i = 0; i < len; ++i)
  15. *(dst++) = *(src++);
  16. *(dst++) = 'X';
  17. return len + 2;
  18. }
  19. struct result_data
  20. : public mariadb_mock_item
  21. {
  22. using row_type = std::vector<const char *>;
  23. using data_type = std::vector<row_type>;
  24. struct internal_data_t
  25. {
  26. std::vector<char*> data;
  27. std::vector<unsigned long> length;
  28. };
  29. using interal_data_vector = std::vector<internal_data_t>;
  30. bool is_stored;
  31. ssize_t affected_rows;
  32. ssize_t return_id;
  33. data_type data;
  34. interal_data_vector internal_data;
  35. template<typename T_data>
  36. result_data(T_data&& p_data, bool p_is_stored, ssize_t p_affected_rows, ssize_t p_return_id)
  37. : data (std::forward<T_data>(p_data))
  38. , is_stored (p_is_stored)
  39. , affected_rows (p_affected_rows)
  40. , return_id (p_return_id)
  41. {
  42. internal_data.resize(data.size());
  43. for (size_t i = 0; i < data.size(); ++i)
  44. {
  45. auto& intern = internal_data.at(i);
  46. auto& d = data.at(i);
  47. intern.data.resize(d.size());
  48. intern.length.resize(d.size());
  49. for (size_t j = 0; j < d.size(); ++j)
  50. {
  51. auto& str = d.at(j);
  52. intern.data[j] = const_cast<char*>(str);
  53. intern.length[j] = static_cast<unsigned long>(str ? strlen(str) : 0);
  54. }
  55. }
  56. }
  57. };
  58. inline MYSQL_RES* next_result()
  59. {
  60. static size_t value = 0x2000;
  61. return reinterpret_cast<MYSQL_RES*>(value++);
  62. }
  63. inline const result_data::data_type& empty_result_data()
  64. {
  65. static const result_data::data_type value;
  66. return value;
  67. }
  68. template<typename T_data = decltype(empty_result_data())>
  69. inline decltype(auto) result_stored(T_data&& data = empty_result_data(), ssize_t affected_rows = -1)
  70. { return result_data(std::forward<T_data>(data), true, affected_rows, -1); }
  71. template<typename T_data = decltype(empty_result_data())>
  72. inline decltype(auto) result_used(T_data&& data = empty_result_data(), ssize_t affected_rows = -1)
  73. { return result_data(std::forward<T_data>(data), false, affected_rows, -1); }
  74. inline decltype(auto) result_affected_rows(ssize_t affected_rows)
  75. { return result_data(empty_result_data(), true, affected_rows, -1); }
  76. inline decltype(auto) result_id(ssize_t id)
  77. { return result_data(empty_result_data(), true, -1, id); }
  78. template<typename T_mock, typename T_result>
  79. inline void expect_query(T_mock& mock, const std::string& query, T_result&& result)
  80. {
  81. EXPECT_CALL(
  82. mock,
  83. mysql_real_query(
  84. reinterpret_cast<MYSQL*>(0x1111),
  85. ::testing::StrEq(query),
  86. query.size()))
  87. .InSequence(mock.sequence);
  88. auto& res = mock.store(std::forward<T_result>(result));
  89. auto ptr = next_result();
  90. if (res.is_stored)
  91. {
  92. EXPECT_CALL(
  93. mock,
  94. mysql_store_result(reinterpret_cast<MYSQL*>(0x1111)))
  95. .InSequence(mock.sequence)
  96. .WillOnce(::testing::Return(ptr));
  97. }
  98. else
  99. {
  100. EXPECT_CALL(
  101. mock,
  102. mysql_use_result(reinterpret_cast<MYSQL*>(0x1111)))
  103. .InSequence(mock.sequence)
  104. .WillOnce(::testing::Return(ptr));
  105. }
  106. if (res.affected_rows >= 0)
  107. {
  108. EXPECT_CALL(
  109. mock,
  110. mysql_affected_rows(reinterpret_cast<MYSQL*>(0x1111)))
  111. .InSequence(mock.sequence)
  112. .WillOnce(::testing::Return(static_cast<unsigned long long>(res.affected_rows)));
  113. }
  114. else if (res.return_id >= 0)
  115. {
  116. EXPECT_CALL(
  117. mock,
  118. mysql_insert_id(reinterpret_cast<MYSQL*>(0x1111)))
  119. .InSequence(mock.sequence)
  120. .WillOnce(::testing::Return(static_cast<unsigned long long>(res.return_id)));
  121. }
  122. if (!res.data.empty())
  123. {
  124. EXPECT_CALL(
  125. mock,
  126. mysql_num_fields(ptr))
  127. .Times(::testing::AnyNumber())
  128. .WillRepeatedly(::testing::Return(res.data.at(0).size()));
  129. }
  130. for (auto& x : res.internal_data)
  131. {
  132. EXPECT_CALL(
  133. mock,
  134. mysql_fetch_row(ptr))
  135. .InSequence(mock.sequence)
  136. .WillOnce(::testing::Return(x.data.data()));
  137. EXPECT_CALL(
  138. mock,
  139. mysql_fetch_lengths(ptr))
  140. .InSequence(mock.sequence)
  141. .WillOnce(::testing::Return(x.length.data()));
  142. }
  143. if (!res.is_stored)
  144. {
  145. EXPECT_CALL(
  146. mock,
  147. mysql_fetch_row(ptr))
  148. .InSequence(mock.sequence)
  149. .WillOnce(::testing::Return(nullptr));
  150. }
  151. EXPECT_CALL(
  152. mock,
  153. mysql_free_result(ptr))
  154. .InSequence(mock.sequence);
  155. }
  156. template<typename T_mock>
  157. inline void expect_query(T_mock& mock, const std::string& query)
  158. { expect_query(mock, query, result_stored()); }