def test_on_msg(get_last_messages, post_msg):
    client = Fake({"_br": {"user_id": 1337}, "host": "stackexchange.com"})

    room_data = chatcommunicate.RoomData(Mock(), -1, False)
    chatcommunicate._rooms[("stackexchange.com", 11540)] = room_data

    chatcommunicate.on_msg(Fake({},
                                spec=chatcommunicate.events.MessageStarred),
                           None)  # don't reply to events we don't care about

    msg1 = Fake(
        {
            "message": {
                "room": {
                    "id": 11540,
                },
                "owner": {
                    "id": 1,
                },
                "parent": None,
                "content": "shoutouts to simpleflips"
            }
        },
        spec=chatcommunicate.events.MessagePosted)

    chatcommunicate.on_msg(msg1, client)

    msg2 = Fake(
        {
            "message": {
                "room": {
                    "id": 11540
                },
                "owner": {
                    "id": 1337
                },
                "id": 999,
                "parent": None,
                "content": "!!/not_actually_a_command"
            }
        },
        spec=chatcommunicate.events.MessagePosted)

    chatcommunicate.on_msg(msg2, client)

    msg3 = Fake(
        {
            "message": {
                "room": {
                    "id": 11540,
                },
                "owner": {
                    "id": 1
                },
                "id": 999,
                "parent": None,
                "content": "!!/a_command"
            }
        },
        spec=chatcommunicate.events.MessagePosted)

    mock_command = Mock(side_effect=lambda *_, **kwargs: "hi"
                        if not kwargs["quiet_action"] else "")
    chatcommunicate._prefix_commands["a_command"] = (mock_command, (0, 0))

    chatcommunicate.on_msg(msg3, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":999 hi"
    mock_command.assert_called_once_with(original_msg=msg3.message,
                                         alias_used="a_command",
                                         quiet_action=False)

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg3.message.content = "!!/a_command-"
    chatcommunicate.on_msg(msg3, client)

    post_msg.assert_not_called()
    mock_command.assert_called_once_with(original_msg=msg3.message,
                                         alias_used="a_command",
                                         quiet_action=True)

    post_msg.reset_mock()
    mock_command.reset_mock()

    chatcommunicate._prefix_commands["a_command"] = (mock_command, (0, 1))
    chatcommunicate.on_msg(msg3, client)

    post_msg.assert_not_called()
    mock_command.assert_called_once_with(None,
                                         original_msg=msg3.message,
                                         alias_used="a_command",
                                         quiet_action=True)

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg3.message.content = "!!/a_command 1 2 3"
    chatcommunicate.on_msg(msg3, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":999 hi"
    mock_command.assert_called_once_with("1 2 3",
                                         original_msg=msg3.message,
                                         alias_used="a_command",
                                         quiet_action=False)

    post_msg.reset_mock()
    mock_command.reset_mock()

    chatcommunicate._prefix_commands["a_command"] = (mock_command, (1, 2))

    msg3.message.content = "!!/a_command"
    chatcommunicate.on_msg(msg3, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":999 Too few arguments."
    mock_command.assert_not_called()

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg3.message.content = "!!/a_command 1 2 oatmeal"
    chatcommunicate.on_msg(msg3, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":999 Too many arguments."
    mock_command.assert_not_called()

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg3.message.content = "!!/a_command- 1 2"
    chatcommunicate.on_msg(msg3, client)

    post_msg.assert_not_called()
    mock_command.assert_called_once_with("1",
                                         "2",
                                         original_msg=msg3.message,
                                         alias_used="a_command",
                                         quiet_action=True)

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg3.message.content = "!!/a_command 3"
    chatcommunicate.on_msg(msg3, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":999 hi"
    mock_command.assert_called_once_with("3",
                                         None,
                                         original_msg=msg3.message,
                                         alias_used="a_command",
                                         quiet_action=False)

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg4 = Fake(
        {
            "message": {
                "room": {
                    "id": 11540,
                },
                "owner": {
                    "id": 1
                },
                "parent": {
                    "owner": {
                        "id": 2
                    }
                },
                "id": 1000,
                "content": "asdf"
            }
        },
        spec=chatcommunicate.events.MessageEdited)

    chatcommunicate.on_msg(msg4, client)

    msg5 = Fake(
        {
            "message": {
                "room": {
                    "id": 11540,
                },
                "owner": {
                    "id": 1
                },
                "parent": {
                    "owner": {
                        "id": 1337
                    }
                },
                "id": 1000,
                "content": "@SmokeDetector why   "
            }
        },
        spec=chatcommunicate.events.MessageEdited)

    chatcommunicate._reply_commands["why"] = (mock_command, (0, 0))

    threw_exception = False

    try:
        chatcommunicate.on_msg(msg5, client)
    except AssertionError:
        threw_exception = True

    assert threw_exception
    mock_command.assert_not_called()
    post_msg.assert_not_called()

    chatcommunicate._reply_commands["why"] = (mock_command, (1, 1))
    chatcommunicate.on_msg(msg5, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":1000 hi"
    mock_command.assert_called_once_with(msg5.message.parent,
                                         original_msg=msg5.message,
                                         alias_used="why",
                                         quiet_action=False)

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg5.message.content = "@SmokeDetector why@!@#-"
    chatcommunicate.on_msg(msg5, client)

    post_msg.assert_not_called()
    mock_command.assert_called_once_with(msg5.message.parent,
                                         original_msg=msg5.message,
                                         alias_used="why",
                                         quiet_action=True)

    msg6 = Fake(
        {
            "message": {
                "room": {
                    "id": 11540,
                },
                "owner": {
                    "id": 1
                },
                "id": 1000,
                "parent": None,
                "content": "sd why - 2why 2why- 2- why- "
            }
        },
        spec=chatcommunicate.events.MessageEdited)

    get_last_messages.side_effect = lambda _, num: (Fake({"id": i})
                                                    for i in range(num))
    chatcommunicate.on_msg(msg6, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][
        1] == ":1000 [:0] hi\n[:1] <skipped>\n[:2] hi\n[:3] hi\n[:4] <processed without return value>\n[:5] <processed without return value>\n[:6] <skipped>\n[:7] <skipped>\n[:8] <processed without return value>"
def test_on_msg(get_last_messages, post_msg):
    client = Fake({
        "_br": {
            "user_id": 1337
        },

        "host": "stackexchange.com"
    })

    room_data = chatcommunicate.RoomData(Mock(), -1, False)
    chatcommunicate._rooms[("stackexchange.com", 11540)] = room_data

    chatcommunicate.on_msg(Fake({}, spec=chatcommunicate.events.MessageStarred), None)  # don't reply to events we don't care about

    msg1 = Fake({
        "message": {
            "room": {
                "id": 11540,
            },

            "owner": {
                "id": 1,
            },

            "parent": None,
            "content": "shoutouts to simpleflips"
        }
    }, spec=chatcommunicate.events.MessagePosted)

    chatcommunicate.on_msg(msg1, client)

    msg2 = Fake({
        "message": {
            "room": {
                "id": 11540
            },

            "owner": {
                "id": 1337
            },

            "id": 999,
            "parent": None,
            "content": "!!/not_actually_a_command"
        }
    }, spec=chatcommunicate.events.MessagePosted)

    chatcommunicate.on_msg(msg2, client)

    msg3 = Fake({
        "message": {
            "room": {
                "id": 11540,
            },

            "owner": {
                "id": 1
            },

            "id": 999,
            "parent": None,
            "content": "!!/a_command"
        }
    }, spec=chatcommunicate.events.MessagePosted)

    mock_command = Mock(side_effect=lambda *_, **kwargs: "hi" if not kwargs["quiet_action"] else "")
    chatcommunicate._commands["prefix"]["a_command"] = (mock_command, (0, 0))

    chatcommunicate.on_msg(msg3, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":999 hi"
    mock_command.assert_called_once_with(original_msg=msg3.message, alias_used="a_command", quiet_action=False)

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg3.message.content = "!!/a_command-"
    chatcommunicate.on_msg(msg3, client)

    post_msg.assert_not_called()
    mock_command.assert_called_once_with(original_msg=msg3.message, alias_used="a_command", quiet_action=True)

    post_msg.reset_mock()
    mock_command.reset_mock()

    chatcommunicate._commands["prefix"]["a_command"] = (mock_command, (0, 1))
    chatcommunicate.on_msg(msg3, client)

    post_msg.assert_not_called()
    mock_command.assert_called_once_with(None, original_msg=msg3.message, alias_used="a_command", quiet_action=True)

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg3.message.content = "!!/a_command 1 2 3"
    chatcommunicate.on_msg(msg3, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":999 hi"
    mock_command.assert_called_once_with("1 2 3", original_msg=msg3.message, alias_used="a_command", quiet_action=False)

    post_msg.reset_mock()
    mock_command.reset_mock()

    chatcommunicate._commands["prefix"]["a_command"] = (mock_command, (1, 2))

    msg3.message.content = "!!/a_command"
    chatcommunicate.on_msg(msg3, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":999 Too few arguments."
    mock_command.assert_not_called()

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg3.message.content = "!!/a_command 1 2 oatmeal"
    chatcommunicate.on_msg(msg3, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":999 Too many arguments."
    mock_command.assert_not_called()

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg3.message.content = "!!/a_command- 1 2"
    chatcommunicate.on_msg(msg3, client)

    post_msg.assert_not_called()
    mock_command.assert_called_once_with("1", "2", original_msg=msg3.message, alias_used="a_command", quiet_action=True)

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg3.message.content = "!!/a_command 3"
    chatcommunicate.on_msg(msg3, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":999 hi"
    mock_command.assert_called_once_with("3", None, original_msg=msg3.message, alias_used="a_command", quiet_action=False)

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg4 = Fake({
        "message": {
            "room": {
                "id": 11540,
            },

            "owner": {
                "id": 1
            },

            "parent": {
                "owner": {
                    "id": 2
                }
            },

            "id": 1000,
            "content": "asdf"
        }
    }, spec=chatcommunicate.events.MessageEdited)

    chatcommunicate.on_msg(msg4, client)

    msg5 = Fake({
        "message": {
            "room": {
                "id": 11540,
            },

            "owner": {
                "id": 1
            },

            "parent": {
                "owner": {
                    "id": 1337
                }
            },

            "id": 1000,
            "content": "@SmokeDetector why   "
        }
    }, spec=chatcommunicate.events.MessageEdited)

    chatcommunicate._commands["reply"]["why"] = (mock_command, (0, 0))

    threw_exception = False

    try:
        chatcommunicate.on_msg(msg5, client)
    except AssertionError:
        threw_exception = True

    assert threw_exception
    mock_command.assert_not_called()
    post_msg.assert_not_called()

    chatcommunicate._commands["reply"]["why"] = (mock_command, (1, 1))
    chatcommunicate.on_msg(msg5, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":1000 hi"
    mock_command.assert_called_once_with(msg5.message.parent, original_msg=msg5.message, alias_used="why", quiet_action=False)

    post_msg.reset_mock()
    mock_command.reset_mock()

    msg5.message.content = "@SmokeDetector why@!@#-"
    chatcommunicate.on_msg(msg5, client)

    post_msg.assert_not_called()
    mock_command.assert_called_once_with(msg5.message.parent, original_msg=msg5.message, alias_used="why", quiet_action=True)

    msg6 = Fake({
        "message": {
            "room": {
                "id": 11540,
            },

            "owner": {
                "id": 1
            },

            "id": 1000,
            "parent": None,
            "content": "sd why - 2why 2why- 2- why- "
        }
    }, spec=chatcommunicate.events.MessageEdited)

    get_last_messages.side_effect = lambda _, num: (Fake({"id": i}) for i in range(num))
    chatcommunicate.on_msg(msg6, client)

    assert post_msg.call_count == 1
    assert post_msg.call_args_list[0][0][0][1] == ":1000 [:0] hi\n[:1] <skipped>\n[:2] hi\n[:3] hi\n[:4] <processed without return value>\n[:5] <processed without return value>\n[:6] <skipped>\n[:7] <skipped>\n[:8] <processed without return value>"