test_cli_transmit.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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
  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_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_mock.assert_called_once_with(lock_spi_device=True)
  108. if base_frequency_hertz is None:
  109. transceiver_mock().__enter__().set_base_frequency_hertz.assert_not_called()
  110. else:
  111. transceiver_mock().__enter__().set_base_frequency_hertz.assert_called_once_with(
  112. base_frequency_hertz
  113. )
  114. if symbol_rate_baud is None:
  115. transceiver_mock().__enter__().set_symbol_rate_baud.assert_not_called()
  116. else:
  117. transceiver_mock().__enter__().set_symbol_rate_baud.assert_called_once_with(
  118. symbol_rate_baud
  119. )
  120. if sync_mode is None:
  121. transceiver_mock().__enter__().set_sync_mode.assert_not_called()
  122. else:
  123. transceiver_mock().__enter__().set_sync_mode.assert_called_once_with(sync_mode)
  124. if packet_length_mode is None:
  125. transceiver_mock().__enter__().set_packet_length_mode.assert_not_called()
  126. else:
  127. transceiver_mock().__enter__().set_packet_length_mode.assert_called_once_with(
  128. packet_length_mode
  129. )
  130. if packet_length_mode == PacketLengthMode.FIXED:
  131. transceiver_mock().__enter__().set_packet_length_bytes.assert_called_with(
  132. len(payload)
  133. )
  134. else:
  135. transceiver_mock().__enter__().set_packet_length_bytes.assert_not_called()
  136. if checksum_disabled:
  137. transceiver_mock().__enter__().disable_checksum.assert_called_once_with()
  138. else:
  139. transceiver_mock().__enter__().disable_checksum.assert_not_called()
  140. @pytest.mark.parametrize(
  141. ("args", "output_power_settings"),
  142. (
  143. ([""], None),
  144. (["", "-p", "198"], [198]), # default
  145. (["", "--output-power", "198"], [198]),
  146. (["", "-p", "0", "198"], [0, 198]), # OOK
  147. (
  148. ["", "-p", "18", "14", "29", "52", "96", "132", "200", "192"],
  149. [18, 14, 29, 52, 96, 132, 200, 192],
  150. ),
  151. ),
  152. )
  153. def test_configure_device_output_power(args, output_power_settings):
  154. with unittest.mock.patch("cc1101.CC1101") as transceiver_mock:
  155. stdin_mock = unittest.mock.MagicMock()
  156. stdin_mock.buffer = io.BytesIO(b"message")
  157. with unittest.mock.patch("sys.stdin", stdin_mock):
  158. with unittest.mock.patch("sys.argv", args):
  159. cc1101._cli._transmit()
  160. transceiver_mock.assert_called_once_with(lock_spi_device=True)
  161. if output_power_settings:
  162. transceiver_mock().__enter__().set_output_power.assert_called_with(
  163. output_power_settings
  164. )
  165. else:
  166. transceiver_mock().__enter__().set_output_power.assert_not_called()
  167. @pytest.mark.parametrize(
  168. ("args", "root_log_level", "log_format"),
  169. (
  170. ([""], logging.INFO, "%(message)s"),
  171. (
  172. ["", "--debug"],
  173. logging.DEBUG,
  174. "%(asctime)s:%(levelname)s:%(name)s:%(funcName)s:%(message)s",
  175. ),
  176. ),
  177. )
  178. def test_root_log_level(args, root_log_level, log_format):
  179. stdin_mock = unittest.mock.MagicMock()
  180. stdin_mock.buffer = io.BytesIO(b"")
  181. with unittest.mock.patch("cc1101.CC1101"), unittest.mock.patch(
  182. "sys.stdin", stdin_mock
  183. ), unittest.mock.patch("sys.argv", args), unittest.mock.patch(
  184. "logging.basicConfig"
  185. ) as logging_basic_config_mock:
  186. cc1101._cli._transmit()
  187. logging_basic_config_mock.assert_called_once()
  188. assert logging_basic_config_mock.call_args[1]["level"] == root_log_level
  189. assert logging_basic_config_mock.call_args[1]["format"] == log_format
  190. @pytest.mark.parametrize("payload", (b"", b"message"))
  191. def test_logging(caplog, payload):
  192. # pylint: disable=too-many-arguments
  193. stdin_mock = unittest.mock.MagicMock()
  194. stdin_mock.buffer = io.BytesIO(payload)
  195. with unittest.mock.patch("sys.stdin", stdin_mock), unittest.mock.patch(
  196. "sys.argv", [""]
  197. ), unittest.mock.patch("cc1101.CC1101") as transceiver_mock, caplog.at_level(
  198. logging.DEBUG
  199. ):
  200. transceiver_mock().__enter__().__str__.return_value = "dummy"
  201. cc1101._cli._transmit()
  202. assert len(caplog.records) == 2
  203. assert caplog.records[0].name == "cc1101._cli"
  204. assert caplog.records[0].levelno == logging.DEBUG
  205. assert caplog.records[0].message.startswith(
  206. "args=Namespace(base_frequency_hertz=None, "
  207. )
  208. assert caplog.record_tuples[1] == ("cc1101._cli", logging.INFO, "dummy")