test_cli_transmit.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. # python-cc1101 - Python Library to Transmit RF Signals via CC1101 Transceivers
  2. #
  3. # Copyright (C) 2020 Fabian Peter Hammerle <fabian@hammerle.me>
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation, either version 3 of the License, or
  8. # any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. import io
  18. import logging
  19. import unittest.mock
  20. import pytest
  21. import cc1101._cli
  22. from cc1101.options import PacketLengthMode, SyncMode
  23. # pylint: disable=protected-access,too-many-positional-arguments
  24. @pytest.mark.parametrize(
  25. (
  26. "args",
  27. "base_frequency_hertz",
  28. "symbol_rate_baud",
  29. "sync_mode",
  30. "packet_length_mode",
  31. "checksum_disabled",
  32. ),
  33. (
  34. ([""], None, None, None, None, False),
  35. (["", "-f", "433920000"], 433920000, None, None, None, False),
  36. (
  37. ["", "--base-frequency-hertz", "868000000"],
  38. 868000000,
  39. None,
  40. None,
  41. None,
  42. False,
  43. ),
  44. (["", "-r", "10000"], None, 10000, None, None, False),
  45. (["", "--symbol-rate-baud", "12345"], None, 12345, None, None, False),
  46. (
  47. ["", "-s", "no-preamble-and-sync-word"],
  48. None,
  49. None,
  50. SyncMode.NO_PREAMBLE_AND_SYNC_WORD,
  51. None,
  52. False,
  53. ),
  54. (
  55. ["", "--sync-mode", "no-preamble-and-sync-word"],
  56. None,
  57. None,
  58. SyncMode.NO_PREAMBLE_AND_SYNC_WORD,
  59. None,
  60. False,
  61. ),
  62. (
  63. ["", "--sync-mode", "transmit-16-match-15-bits"],
  64. None,
  65. None,
  66. SyncMode.TRANSMIT_16_MATCH_15_BITS,
  67. None,
  68. False,
  69. ),
  70. (["", "-l", "fixed"], None, None, None, PacketLengthMode.FIXED, False),
  71. (
  72. ["", "--packet-length-mode", "fixed"],
  73. None,
  74. None,
  75. None,
  76. PacketLengthMode.FIXED,
  77. False,
  78. ),
  79. (
  80. ["", "--packet-length-mode", "variable"],
  81. None,
  82. None,
  83. None,
  84. PacketLengthMode.VARIABLE,
  85. False,
  86. ),
  87. (["", "--disable-checksum"], None, None, None, None, True),
  88. ),
  89. )
  90. @pytest.mark.parametrize("payload", (b"", b"message"))
  91. def test_configure_device(
  92. args,
  93. base_frequency_hertz,
  94. symbol_rate_baud,
  95. sync_mode,
  96. packet_length_mode,
  97. checksum_disabled,
  98. payload,
  99. ):
  100. # pylint: disable=too-many-arguments
  101. with unittest.mock.patch("cc1101.CC1101") as transceiver_class_mock:
  102. stdin_mock = unittest.mock.MagicMock()
  103. stdin_mock.buffer = io.BytesIO(payload)
  104. with unittest.mock.patch("sys.stdin", stdin_mock):
  105. with unittest.mock.patch("sys.argv", args):
  106. cc1101._cli._transmit()
  107. transceiver_class_mock.assert_called_once_with(lock_spi_device=True)
  108. with transceiver_class_mock() as transceiver_mock:
  109. pass
  110. if base_frequency_hertz is None:
  111. transceiver_mock.set_base_frequency_hertz.assert_not_called()
  112. else:
  113. transceiver_mock.set_base_frequency_hertz.assert_called_once_with(
  114. base_frequency_hertz
  115. )
  116. if symbol_rate_baud is None:
  117. transceiver_mock.set_symbol_rate_baud.assert_not_called()
  118. else:
  119. transceiver_mock.set_symbol_rate_baud.assert_called_once_with(symbol_rate_baud)
  120. if sync_mode is None:
  121. transceiver_mock.set_sync_mode.assert_not_called()
  122. else:
  123. transceiver_mock.set_sync_mode.assert_called_once_with(sync_mode)
  124. if packet_length_mode is None: # pylint: disable=duplicate-code
  125. transceiver_mock.set_packet_length_mode.assert_not_called()
  126. else:
  127. transceiver_mock.set_packet_length_mode.assert_called_once_with(
  128. packet_length_mode
  129. )
  130. if packet_length_mode == PacketLengthMode.FIXED:
  131. transceiver_mock.set_packet_length_bytes.assert_called_with(len(payload))
  132. else:
  133. transceiver_mock.set_packet_length_bytes.assert_not_called()
  134. if checksum_disabled:
  135. transceiver_mock.disable_checksum.assert_called_once_with()
  136. else:
  137. transceiver_mock.disable_checksum.assert_not_called()
  138. @pytest.mark.parametrize(
  139. ("args", "output_power_settings"),
  140. (
  141. ([""], None),
  142. (["", "-p", "198"], [198]), # default
  143. (["", "--output-power", "198"], [198]),
  144. (["", "-p", "0", "198"], [0, 198]), # OOK
  145. (
  146. ["", "-p", "18", "14", "29", "52", "96", "132", "200", "192"],
  147. [18, 14, 29, 52, 96, 132, 200, 192],
  148. ),
  149. ),
  150. )
  151. def test_configure_device_output_power(args, output_power_settings):
  152. with unittest.mock.patch("cc1101.CC1101") as transceiver_class_mock:
  153. stdin_mock = unittest.mock.MagicMock()
  154. stdin_mock.buffer = io.BytesIO(b"message")
  155. with unittest.mock.patch("sys.stdin", stdin_mock):
  156. with unittest.mock.patch("sys.argv", args):
  157. cc1101._cli._transmit()
  158. transceiver_class_mock.assert_called_once_with(lock_spi_device=True)
  159. with transceiver_class_mock() as transceiver_mock:
  160. pass
  161. if output_power_settings:
  162. transceiver_mock.set_output_power.assert_called_with(output_power_settings)
  163. else:
  164. transceiver_mock.set_output_power.assert_not_called()
  165. @pytest.mark.parametrize(
  166. ("args", "root_log_level", "log_format"),
  167. (
  168. ([""], logging.INFO, "%(message)s"),
  169. (
  170. ["", "--debug"],
  171. logging.DEBUG,
  172. "%(asctime)s:%(levelname)s:%(name)s:%(funcName)s:%(message)s",
  173. ),
  174. ),
  175. )
  176. def test_root_log_level(args, root_log_level, log_format):
  177. stdin_mock = unittest.mock.MagicMock()
  178. stdin_mock.buffer = io.BytesIO(b"")
  179. with unittest.mock.patch("cc1101.CC1101"), unittest.mock.patch(
  180. "sys.stdin", stdin_mock
  181. ), unittest.mock.patch("sys.argv", args), unittest.mock.patch(
  182. "logging.basicConfig"
  183. ) as logging_basic_config_mock:
  184. cc1101._cli._transmit()
  185. logging_basic_config_mock.assert_called_once()
  186. assert logging_basic_config_mock.call_args[1]["level"] == root_log_level
  187. assert logging_basic_config_mock.call_args[1]["format"] == log_format
  188. @pytest.mark.parametrize("payload", (b"", b"message"))
  189. def test_logging(caplog, payload):
  190. # pylint: disable=too-many-arguments
  191. stdin_mock = unittest.mock.MagicMock()
  192. stdin_mock.buffer = io.BytesIO(payload)
  193. with unittest.mock.patch("sys.stdin", stdin_mock), unittest.mock.patch(
  194. "sys.argv", [""]
  195. ), unittest.mock.patch("cc1101.CC1101") as transceiver_class_mock, caplog.at_level(
  196. logging.DEBUG
  197. ):
  198. with transceiver_class_mock() as transceiver_mock:
  199. transceiver_mock.__str__.return_value = "dummy"
  200. cc1101._cli._transmit()
  201. assert len(caplog.records) == 2
  202. assert caplog.records[0].name == "cc1101._cli"
  203. assert caplog.records[0].levelno == logging.DEBUG
  204. assert caplog.records[0].message.startswith(
  205. "args=Namespace(base_frequency_hertz=None, "
  206. )
  207. assert caplog.record_tuples[1] == ("cc1101._cli", logging.INFO, "dummy")