[Include] ut_mock_players - y_testing mock player generator
#1

ut_mock_players

Player mocking system for unit tests


y_testing is really powerful library, but most of you people won't use it ever - therefore ut_mock_players isn't for you. For the rest of you folks, sometimes you might need to simulate a lot of users on your server at once. Some people will use NPC's to do that, other will hire cheap Mexican labour. However, I'm not clever enough to do that, so I've started to overwrite functions from a_players. There is a metric alot of them, and I've done only few so far - this gives you idea how to do more of them, and even with this limited toolset, it's pretty helpful.

Dependencies


Of course y_testing, and y_utils. Later on there will be y_iterate as well, so you can test with less than MAX_PLAYERS at once.

How to use that thing


pawn Code:
#define RUN_TESTS
#include <ut_mock_players>

main() {
    new
        tests,
        fails,
        func[33];
    Testing_Run(tests, fails, func);
}

public OnPlayerConnect(playerid)
{
    printf("Player %d connected!", playerid);
    SetPlayerScore(playerid, GetPlayerScore(playerid) + 25);
    return 1;
}

Test:Connection()
{
    //Randomly selected number
    new
        playerid = 256, score = GetPlayerScore(playerid);

    ASSERT(score == 0);
    printf("Player score before: %d", score);
    OnPlayerConnect(playerid);

    score = GetPlayerScore(playerid);
    ASSERT(score == 25);
    printf("Player score after: %d", score);
}

#include <ut_mock_players>
Wait, what, why is it included twice? Well, explanation is simple - you might want to run tests aimed at live players. Then, you want your normal functions back - and to do this, simply include this file again.

Very important note! It is essential to compile with suppresed warnings 203-206. "Why?" you might ask. Normally when you grab, for example, user position using GetPlayerPos, like:
pawn Code:
new Float:X, Float:Y, Float:Z;
GetPlayerPos(playerid, X, Y, Z);
All of your variables are considered being "used" by the compiler, even if you don't touch Z variable at all. Behind the scenes, ut_mock_players substitutes function call with standard assignmnent, resulting in code:
pawn Code:
new Float:X, Float:Y, Float:Z;
(X = MockPlayer[playerid][mu_pos][0], Y = MockPlayer[playerid][mu_pos][1], Z = MockPlayer[playerid][mu_pos][2]);
Now, if you don't use Z variable in your code, for compiler it is unused. I could rewrite code to use standard function hook, but assuming your code itself doesn't have any synax errors (passing function instead of variable reference), suppressing warning has lesser cost. Also, some functions are completely overridden, like IsPlayerConnected, which returns constant 1. That creates code like
pawn Code:
if(1) { /*(...)*/ }
Causing "expression has no effect" warnings. (I might change that to grab MockPlayer[playerid][mu_connected], but that's for future reference)

Example compiler call (used by me):
Quote:

pawncc "$file" -;+ -v2 -w203 -w204 -w205 -w206 -d3

Download


Gist link
Pastebin mirror


Save as ut_mock_players.inc in your pawno/includes folder. Compiled with Zeex patches, but it should compile nicely with normal pawncc.

Changelog


Initial commit
- Few functions
- Most of user structure initialised

Update 2014-01-28
- Added information about compiler flags
- Added roadmap

Issues

Working with static data, instead with live players has its toll. Creating for example GetPlayerTargetPlayer requires some additional computation, and will be really off in many cases. You have to do anything by hand - setting the player camera, position, using callbacks (well, unit tests should be consistent across runs, so that's a good thing though once you get that done).

Roadmap

- Creating separate logs for client messages sent to specific players
- Override of all player functions, with simulated actions like vehicle entering
- Changing IsPlayerConnected behaviour

More


If you have any questions, this thread is yours. I'll add functions on the fly as needed for me. Feel free to fork the gist, I'd really appreciate help with it.
Reply
#2

With pleasure (without y_testing this wouldn't have any reason to exist!) - however I'm not sure if I'll be able to stick to your coding stantards though
Reply
#3

How should I go about integrating it into YSI? Request a pull request on YSI.tl branch or something? Where would it be placed?

Other than that, I have to rewrite most of those macros to functions, because using things from heap in y_inline functions doesn't work as intended (when normal function does).
Reply
#4

Amazing, this will surely be the easiest way to test out several stuff without the need of any tester.
Reply
#5

I've been fiddling with that the last few days, and I've hit a brick wall. Plugins (like streamer) are naturally not suspectible to macros (using sampgdk to access native functions directly). That's inconvinient, as I don't want to lose the plugin functionality for testing. This would require either doing this include as a plugin and messing with the native function addresses, or use some amx_assembly black magic (and do the same). I don't know if I should go that far, or keep this include for simple testing, and use NPC's for some more player-like testing.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)