From 97bf3f34bce40a7e957fc1b72b1628031bcfb642 Mon Sep 17 00:00:00 2001 From: askmeaboutloom Date: Sun, 6 Aug 2023 09:13:05 +0200 Subject: [PATCH] Add recording round trip test Replacing the hard-coded recording tests that faltered from the protocol changes. This solution just generates messages and then does some round trips with them, which caught a number of bugs already. --- .../generators/protogen/messages.h.jinja | 19 + .../generators/protogen/protogen_drawdance.py | 8 + src/drawdance/libcommon/CMakeLists.txt | 6 +- src/drawdance/libmsg/CMakeLists.txt | 12 +- src/drawdance/libmsg/dpmsg/messages.h | 166 +++ .../libmsg/test/read_write_roundtrip.c | 1045 +++++++++++++++-- src/drawdance/libtest/CMakeLists.txt | 4 +- 7 files changed, 1158 insertions(+), 102 deletions(-) diff --git a/src/drawdance/generators/protogen/messages.h.jinja b/src/drawdance/generators/protogen/messages.h.jinja index 7b5e3d59d5..7e5f762c84 100644 --- a/src/drawdance/generators/protogen/messages.h.jinja +++ b/src/drawdance/generators/protogen/messages.h.jinja @@ -84,12 +84,24 @@ DP_Message *DP_message_parse_body(DP_MessageType type, unsigned int context_id, #define {{ message.enum_name }}_STATIC_LENGTH {{ message.static_payload_length }} {% for f in message.fields %} + {% if f.min != f.max %} + + #define {{ message.enum_name }}_{{ f.func_name|upper }}_MIN_{{ f.array_size_name|upper }} {{ f.min }} + #define {{ message.enum_name }}_{{ f.func_name|upper }}_MAX_{{ f.array_size_name|upper }} {{ f.max }} + {% endif %} {% if f.flags %} {% for flag in f.flags %} #define {{ flag.define_name }} 0x{{ '%.x'|format(flag.value) }} {% endfor %} + #define DP_{{ message.func_name|upper }}_NUM_{{ f.func_name|upper }} {{ f.flags|length }} + #define DP_{{ message.func_name|upper }}_ALL_{{ f.func_name|upper }} \ + {% for flag in f.flags %} + {{ flag.define_name }}{% if not loop.last %}, \{% endif %} + + {% endfor %} + const char *DP_{{ message.func_name }}_{{ f.func_name }}_flag_name(unsigned int value); {% endif %} {% if f.variants %} @@ -98,6 +110,13 @@ DP_Message *DP_message_parse_body(DP_MessageType type, unsigned int context_id, #define {{ variant.define_name }} {{ variant.value }} {% endfor %} + #define DP_{{ message.func_name|upper }}_NUM_{{ f.func_name|upper }} {{ f.variants|length }} + #define DP_{{ message.func_name|upper }}_ALL_{{ f.func_name|upper }} \ + {% for variant in f.variants %} + {{ variant.define_name }}{% if not loop.last %}, \{% endif %} + + {% endfor %} + const char *DP_{{ message.func_name }}_{{ f.func_name }}_variant_name(unsigned int value); {% endif %} {% endfor %} diff --git a/src/drawdance/generators/protogen/protogen_drawdance.py b/src/drawdance/generators/protogen/protogen_drawdance.py index d408fcf2a2..aeca8a21fd 100755 --- a/src/drawdance/generators/protogen/protogen_drawdance.py +++ b/src/drawdance/generators/protogen/protogen_drawdance.py @@ -1001,6 +1001,14 @@ def __init__(self, message, field): else: self.sub = None + divisor = self.deserialize_field_divisor + if divisor: + self.min = field.min_len // divisor + self.max = field.max_len // divisor + else: + self.min = field.min_len + self.max = field.max_len + def access(self, subject): return self.type.access(self, subject) diff --git a/src/drawdance/libcommon/CMakeLists.txt b/src/drawdance/libcommon/CMakeLists.txt index 2fcd7ee2f2..03c83a8762 100644 --- a/src/drawdance/libcommon/CMakeLists.txt +++ b/src/drawdance/libcommon/CMakeLists.txt @@ -88,6 +88,10 @@ endif() if(TESTS) add_dptest_targets(common dptest - "test/base64.c;test/file.c;test/queue.c;test/rect.c;test/vector.c" + test/base64.c + test/file.c + test/queue.c + test/rect.c + test/vector.c ) endif() diff --git a/src/drawdance/libmsg/CMakeLists.txt b/src/drawdance/libmsg/CMakeLists.txt index ba9a1d6780..bf9300148f 100644 --- a/src/drawdance/libmsg/CMakeLists.txt +++ b/src/drawdance/libmsg/CMakeLists.txt @@ -26,10 +26,10 @@ dp_target_sources(dpmsg ) target_include_directories(dpmsg PUBLIC ${CMAKE_CURRENT_LIST_DIR}) -target_link_libraries(dpmsg PRIVATE dpcommon uthash parson) +target_link_libraries(dpmsg PUBLIC dpcommon uthash parson) -# if(BUILD_TESTS) -# add_dptest_targets(msg dptest -# test/read_write_roundtrip.c -# ) -# endif() +if(TESTS) + add_dptest_targets(msg dptest + test/read_write_roundtrip.c + ) +endif() diff --git a/src/drawdance/libmsg/dpmsg/messages.h b/src/drawdance/libmsg/dpmsg/messages.h index 65776914bb..55d7bd64e2 100644 --- a/src/drawdance/libmsg/dpmsg/messages.h +++ b/src/drawdance/libmsg/dpmsg/messages.h @@ -153,6 +153,9 @@ DP_Message *DP_message_parse_body(DP_MessageType type, unsigned int context_id, #define DP_MSG_SERVER_COMMAND_STATIC_LENGTH 0 +#define DP_MSG_SERVER_COMMAND_MSG_MIN_LEN 0 +#define DP_MSG_SERVER_COMMAND_MSG_MAX_LEN 65535 + typedef struct DP_MsgServerCommand DP_MsgServerCommand; DP_Message *DP_msg_server_command_new(unsigned int context_id, @@ -189,8 +192,16 @@ size_t DP_msg_server_command_msg_len(const DP_MsgServerCommand *msc); #define DP_MSG_DISCONNECT_REASON_SHUTDOWN 2 #define DP_MSG_DISCONNECT_REASON_OTHER 3 +#define DP_MSG_DISCONNECT_NUM_REASON 4 +#define DP_MSG_DISCONNECT_ALL_REASON \ + DP_MSG_DISCONNECT_REASON_ERROR, DP_MSG_DISCONNECT_REASON_KICK, \ + DP_MSG_DISCONNECT_REASON_SHUTDOWN, DP_MSG_DISCONNECT_REASON_OTHER + const char *DP_msg_disconnect_reason_variant_name(unsigned int value); +#define DP_MSG_DISCONNECT_MESSAGE_MIN_LEN 0 +#define DP_MSG_DISCONNECT_MESSAGE_MAX_LEN 65534 + typedef struct DP_MsgDisconnect DP_MsgDisconnect; DP_Message *DP_msg_disconnect_new(unsigned int context_id, uint8_t reason, @@ -263,8 +274,18 @@ bool DP_msg_ping_is_pong(const DP_MsgPing *mp); #define DP_MSG_JOIN_FLAGS_MOD 0x2 #define DP_MSG_JOIN_FLAGS_BOT 0x4 +#define DP_MSG_JOIN_NUM_FLAGS 3 +#define DP_MSG_JOIN_ALL_FLAGS \ + DP_MSG_JOIN_FLAGS_AUTH, DP_MSG_JOIN_FLAGS_MOD, DP_MSG_JOIN_FLAGS_BOT + const char *DP_msg_join_flags_flag_name(unsigned int value); +#define DP_MSG_JOIN_NAME_MIN_LEN 1 +#define DP_MSG_JOIN_NAME_MAX_LEN 256 + +#define DP_MSG_JOIN_AVATAR_MIN_SIZE 0 +#define DP_MSG_JOIN_AVATAR_MAX_SIZE 65533 + typedef struct DP_MsgJoin DP_MsgJoin; DP_Message *DP_msg_join_new(unsigned int context_id, uint8_t flags, @@ -329,6 +350,9 @@ DP_Message *DP_msg_leave_parse(unsigned int context_id, DP_TextReader *reader); #define DP_MSG_SESSION_OWNER_STATIC_LENGTH 0 +#define DP_MSG_SESSION_OWNER_USERS_MIN_COUNT 0 +#define DP_MSG_SESSION_OWNER_USERS_MAX_COUNT 255 + typedef struct DP_MsgSessionOwner DP_MsgSessionOwner; DP_Message *DP_msg_session_owner_new(unsigned int context_id, @@ -365,6 +389,9 @@ int DP_msg_session_owner_users_count(const DP_MsgSessionOwner *mso); #define DP_MSG_CHAT_TFLAGS_BYPASS 0x1 +#define DP_MSG_CHAT_NUM_TFLAGS 1 +#define DP_MSG_CHAT_ALL_TFLAGS DP_MSG_CHAT_TFLAGS_BYPASS + const char *DP_msg_chat_tflags_flag_name(unsigned int value); #define DP_MSG_CHAT_OFLAGS_SHOUT 0x1 @@ -372,8 +399,16 @@ const char *DP_msg_chat_tflags_flag_name(unsigned int value); #define DP_MSG_CHAT_OFLAGS_PIN 0x4 #define DP_MSG_CHAT_OFLAGS_ALERT 0x8 +#define DP_MSG_CHAT_NUM_OFLAGS 4 +#define DP_MSG_CHAT_ALL_OFLAGS \ + DP_MSG_CHAT_OFLAGS_SHOUT, DP_MSG_CHAT_OFLAGS_ACTION, \ + DP_MSG_CHAT_OFLAGS_PIN, DP_MSG_CHAT_OFLAGS_ALERT + const char *DP_msg_chat_oflags_flag_name(unsigned int value); +#define DP_MSG_CHAT_MESSAGE_MIN_LEN 0 +#define DP_MSG_CHAT_MESSAGE_MAX_LEN 65533 + typedef struct DP_MsgChat DP_MsgChat; DP_Message *DP_msg_chat_new(unsigned int context_id, uint8_t tflags, @@ -415,6 +450,9 @@ size_t DP_msg_chat_message_len(const DP_MsgChat *mc); #define DP_MSG_TRUSTED_USERS_STATIC_LENGTH 0 +#define DP_MSG_TRUSTED_USERS_USERS_MIN_COUNT 0 +#define DP_MSG_TRUSTED_USERS_USERS_MAX_COUNT 255 + typedef struct DP_MsgTrustedUsers DP_MsgTrustedUsers; DP_Message *DP_msg_trusted_users_new(unsigned int context_id, @@ -475,6 +513,9 @@ DP_Message *DP_msg_soft_reset_parse(unsigned int context_id, #define DP_MSG_PRIVATE_CHAT_STATIC_LENGTH 2 +#define DP_MSG_PRIVATE_CHAT_MESSAGE_MIN_LEN 0 +#define DP_MSG_PRIVATE_CHAT_MESSAGE_MAX_LEN 65533 + typedef struct DP_MsgPrivateChat DP_MsgPrivateChat; DP_Message *DP_msg_private_chat_new(unsigned int context_id, uint8_t target, @@ -607,6 +648,9 @@ int32_t DP_msg_move_pointer_y(const DP_MsgMovePointer *mmp); #define DP_MSG_MARKER_STATIC_LENGTH 0 +#define DP_MSG_MARKER_TEXT_MIN_LEN 0 +#define DP_MSG_MARKER_TEXT_MAX_LEN 65535 + typedef struct DP_MsgMarker DP_MsgMarker; DP_Message *DP_msg_marker_new(unsigned int context_id, const char *text_value, @@ -636,6 +680,9 @@ size_t DP_msg_marker_text_len(const DP_MsgMarker *mm); #define DP_MSG_USER_ACL_STATIC_LENGTH 0 +#define DP_MSG_USER_ACL_USERS_MIN_COUNT 0 +#define DP_MSG_USER_ACL_USERS_MAX_COUNT 255 + typedef struct DP_MsgUserAcl DP_MsgUserAcl; DP_Message *DP_msg_user_acl_new(unsigned int context_id, @@ -677,6 +724,9 @@ int DP_msg_user_acl_users_count(const DP_MsgUserAcl *mua); #define DP_MSG_LAYER_ACL_STATIC_LENGTH 3 +#define DP_MSG_LAYER_ACL_EXCLUSIVE_MIN_COUNT 0 +#define DP_MSG_LAYER_ACL_EXCLUSIVE_MAX_COUNT 255 + typedef struct DP_MsgLayerAcl DP_MsgLayerAcl; DP_Message *DP_msg_layer_acl_new(unsigned int context_id, uint16_t id, @@ -715,6 +765,9 @@ int DP_msg_layer_acl_exclusive_count(const DP_MsgLayerAcl *mla); #define DP_MSG_FEATURE_ACCESS_LEVELS_STATIC_LENGTH 0 +#define DP_MSG_FEATURE_ACCESS_LEVELS_FEATURE_TIERS_MIN_COUNT 1 +#define DP_MSG_FEATURE_ACCESS_LEVELS_FEATURE_TIERS_MAX_COUNT 255 + typedef struct DP_MsgFeatureAccessLevels DP_MsgFeatureAccessLevels; DP_Message *DP_msg_feature_access_levels_new( @@ -774,6 +827,9 @@ uint16_t DP_msg_default_layer_id(const DP_MsgDefaultLayer *mdl); #define DP_MSG_FILTERED_STATIC_LENGTH 0 +#define DP_MSG_FILTERED_MESSAGE_MIN_SIZE 0 +#define DP_MSG_FILTERED_MESSAGE_MAX_SIZE 65535 + typedef struct DP_MsgFiltered DP_MsgFiltered; DP_Message *DP_msg_filtered_new(unsigned int context_id, @@ -841,8 +897,14 @@ uint8_t DP_msg_undo_depth_depth(const DP_MsgUndoDepth *mud); #define DP_MSG_DATA_TYPE_USER_INFO 0 +#define DP_MSG_DATA_NUM_TYPE 1 +#define DP_MSG_DATA_ALL_TYPE DP_MSG_DATA_TYPE_USER_INFO + const char *DP_msg_data_type_variant_name(unsigned int value); +#define DP_MSG_DATA_BODY_MIN_SIZE 0 +#define DP_MSG_DATA_BODY_MAX_SIZE 65533 + typedef struct DP_MsgData DP_MsgData; DP_Message *DP_msg_data_new(unsigned int context_id, uint8_t type, @@ -885,8 +947,22 @@ size_t DP_msg_data_body_size(const DP_MsgData *md); #define DP_MSG_LOCAL_CHANGE_TYPE_TRACK_VISIBILITY 6 #define DP_MSG_LOCAL_CHANGE_TYPE_TRACK_ONION_SKIN 7 +#define DP_MSG_LOCAL_CHANGE_NUM_TYPE 8 +#define DP_MSG_LOCAL_CHANGE_ALL_TYPE \ + DP_MSG_LOCAL_CHANGE_TYPE_LAYER_VISIBILITY, \ + DP_MSG_LOCAL_CHANGE_TYPE_BACKGROUND_TILE, \ + DP_MSG_LOCAL_CHANGE_TYPE_VIEW_MODE, \ + DP_MSG_LOCAL_CHANGE_TYPE_ACTIVE_LAYER, \ + DP_MSG_LOCAL_CHANGE_TYPE_ACTIVE_FRAME, \ + DP_MSG_LOCAL_CHANGE_TYPE_ONION_SKINS, \ + DP_MSG_LOCAL_CHANGE_TYPE_TRACK_VISIBILITY, \ + DP_MSG_LOCAL_CHANGE_TYPE_TRACK_ONION_SKIN + const char *DP_msg_local_change_type_variant_name(unsigned int value); +#define DP_MSG_LOCAL_CHANGE_BODY_MIN_SIZE 0 +#define DP_MSG_LOCAL_CHANGE_BODY_MAX_SIZE 65534 + typedef struct DP_MsgLocalChange DP_MsgLocalChange; DP_Message *DP_msg_local_change_new(unsigned int context_id, uint8_t type, @@ -1005,8 +1081,15 @@ int32_t DP_msg_canvas_resize_left(const DP_MsgCanvasResize *mcr); #define DP_MSG_LAYER_CREATE_FLAGS_COPY 0x1 #define DP_MSG_LAYER_CREATE_FLAGS_INSERT 0x2 +#define DP_MSG_LAYER_CREATE_NUM_FLAGS 2 +#define DP_MSG_LAYER_CREATE_ALL_FLAGS \ + DP_MSG_LAYER_CREATE_FLAGS_COPY, DP_MSG_LAYER_CREATE_FLAGS_INSERT + const char *DP_msg_layer_create_flags_flag_name(unsigned int value); +#define DP_MSG_LAYER_CREATE_TITLE_MIN_LEN 0 +#define DP_MSG_LAYER_CREATE_TITLE_MAX_LEN 65526 + typedef struct DP_MsgLayerCreate DP_MsgLayerCreate; DP_Message *DP_msg_layer_create_new(unsigned int context_id, uint16_t id, @@ -1058,6 +1141,11 @@ size_t DP_msg_layer_create_title_len(const DP_MsgLayerCreate *mlc); #define DP_MSG_LAYER_ATTRIBUTES_FLAGS_FIXED 0x2 #define DP_MSG_LAYER_ATTRIBUTES_FLAGS_ISOLATED 0x4 +#define DP_MSG_LAYER_ATTRIBUTES_NUM_FLAGS 3 +#define DP_MSG_LAYER_ATTRIBUTES_ALL_FLAGS \ + DP_MSG_LAYER_ATTRIBUTES_FLAGS_CENSOR, DP_MSG_LAYER_ATTRIBUTES_FLAGS_FIXED, \ + DP_MSG_LAYER_ATTRIBUTES_FLAGS_ISOLATED + const char *DP_msg_layer_attributes_flags_flag_name(unsigned int value); typedef struct DP_MsgLayerAttributes DP_MsgLayerAttributes; @@ -1094,6 +1182,9 @@ uint8_t DP_msg_layer_attributes_blend(const DP_MsgLayerAttributes *mla); #define DP_MSG_LAYER_RETITLE_STATIC_LENGTH 2 +#define DP_MSG_LAYER_RETITLE_TITLE_MIN_LEN 0 +#define DP_MSG_LAYER_RETITLE_TITLE_MAX_LEN 65533 + typedef struct DP_MsgLayerRetitle DP_MsgLayerRetitle; DP_Message *DP_msg_layer_retitle_new(unsigned int context_id, uint16_t id, @@ -1138,6 +1229,9 @@ size_t DP_msg_layer_retitle_title_len(const DP_MsgLayerRetitle *mlr); #define DP_MSG_LAYER_ORDER_STATIC_LENGTH 0 +#define DP_MSG_LAYER_ORDER_LAYERS_MIN_COUNT 0 +#define DP_MSG_LAYER_ORDER_LAYERS_MAX_COUNT 32767 + typedef struct DP_MsgLayerOrder DP_MsgLayerOrder; DP_Message *DP_msg_layer_order_new(unsigned int context_id, @@ -1242,6 +1336,9 @@ bool DP_msg_layer_visibility_visible(const DP_MsgLayerVisibility *mlv); #define DP_MSG_PUT_IMAGE_STATIC_LENGTH 19 +#define DP_MSG_PUT_IMAGE_IMAGE_MIN_SIZE 0 +#define DP_MSG_PUT_IMAGE_IMAGE_MAX_SIZE 65516 + typedef struct DP_MsgPutImage DP_MsgPutImage; DP_Message * @@ -1440,8 +1537,17 @@ uint16_t DP_msg_annotation_reshape_h(const DP_MsgAnnotationReshape *mar); #define DP_MSG_ANNOTATION_EDIT_FLAGS_VALIGN_CENTER 0x2 #define DP_MSG_ANNOTATION_EDIT_FLAGS_VALIGN_BOTTOM 0x4 +#define DP_MSG_ANNOTATION_EDIT_NUM_FLAGS 3 +#define DP_MSG_ANNOTATION_EDIT_ALL_FLAGS \ + DP_MSG_ANNOTATION_EDIT_FLAGS_PROTECT, \ + DP_MSG_ANNOTATION_EDIT_FLAGS_VALIGN_CENTER, \ + DP_MSG_ANNOTATION_EDIT_FLAGS_VALIGN_BOTTOM + const char *DP_msg_annotation_edit_flags_flag_name(unsigned int value); +#define DP_MSG_ANNOTATION_EDIT_TEXT_MIN_LEN 0 +#define DP_MSG_ANNOTATION_EDIT_TEXT_MAX_LEN 65527 + typedef struct DP_MsgAnnotationEdit DP_MsgAnnotationEdit; DP_Message *DP_msg_annotation_edit_new(unsigned int context_id, uint16_t id, @@ -1528,6 +1634,9 @@ uint16_t DP_msg_annotation_delete_id(const DP_MsgAnnotationDelete *mad); #define DP_MSG_MOVE_REGION_STATIC_LENGTH 50 +#define DP_MSG_MOVE_REGION_MASK_MIN_SIZE 0 +#define DP_MSG_MOVE_REGION_MASK_MAX_SIZE 65485 + typedef struct DP_MsgMoveRegion DP_MsgMoveRegion; DP_Message * @@ -1595,6 +1704,9 @@ size_t DP_msg_move_region_mask_size(const DP_MsgMoveRegion *mmr); #define DP_MSG_PUT_TILE_STATIC_LENGTH 9 +#define DP_MSG_PUT_TILE_IMAGE_MIN_SIZE 0 +#define DP_MSG_PUT_TILE_IMAGE_MAX_SIZE 65526 + typedef struct DP_MsgPutTile DP_MsgPutTile; DP_Message * @@ -1639,6 +1751,9 @@ size_t DP_msg_put_tile_image_size(const DP_MsgPutTile *mpt); #define DP_MSG_CANVAS_BACKGROUND_STATIC_LENGTH 0 +#define DP_MSG_CANVAS_BACKGROUND_IMAGE_MIN_SIZE 0 +#define DP_MSG_CANVAS_BACKGROUND_IMAGE_MAX_SIZE 65535 + typedef struct DP_MsgCanvasBackground DP_MsgCanvasBackground; DP_Message * @@ -1675,6 +1790,9 @@ size_t DP_msg_canvas_background_image_size(const DP_MsgCanvasBackground *mcb); #define DP_MSG_DRAW_DABS_CLASSIC_STATIC_LENGTH 15 +#define DP_MSG_DRAW_DABS_CLASSIC_DABS_MIN_COUNT 1 +#define DP_MSG_DRAW_DABS_CLASSIC_DABS_MAX_COUNT 10920 + #define DP_MSG_DRAW_DABS_CLASSIC_DABS_MAX 10920 typedef struct DP_ClassicDab DP_ClassicDab; @@ -1740,6 +1858,9 @@ int DP_msg_draw_dabs_classic_dabs_count(const DP_MsgDrawDabsClassic *mddc); #define DP_MSG_DRAW_DABS_PIXEL_STATIC_LENGTH 15 +#define DP_MSG_DRAW_DABS_PIXEL_DABS_MIN_COUNT 1 +#define DP_MSG_DRAW_DABS_PIXEL_DABS_MAX_COUNT 16380 + #define DP_MSG_DRAW_DABS_PIXEL_DABS_MAX 16380 typedef struct DP_PixelDab DP_PixelDab; @@ -1828,6 +1949,9 @@ DP_MsgDrawDabsPixel *DP_msg_draw_dabs_pixel_square_cast(DP_Message *msg); #define DP_MSG_DRAW_DABS_MYPAINT_STATIC_LENGTH 18 +#define DP_MSG_DRAW_DABS_MYPAINT_DABS_MIN_COUNT 1 +#define DP_MSG_DRAW_DABS_MYPAINT_DABS_MAX_COUNT 8189 + #define DP_MSG_DRAW_DABS_MYPAINT_DABS_MAX 8189 typedef struct DP_MyPaintDab DP_MyPaintDab; @@ -1907,6 +2031,9 @@ int DP_msg_draw_dabs_mypaint_dabs_count(const DP_MsgDrawDabsMyPaint *mddmp); #define DP_MSG_MOVE_RECT_STATIC_LENGTH 28 +#define DP_MSG_MOVE_RECT_MASK_MIN_SIZE 0 +#define DP_MSG_MOVE_RECT_MASK_MAX_SIZE 65507 + typedef struct DP_MsgMoveRect DP_MsgMoveRect; DP_Message *DP_msg_move_rect_new(unsigned int context_id, uint16_t layer, @@ -1964,6 +2091,12 @@ size_t DP_msg_move_rect_mask_size(const DP_MsgMoveRect *mmr); #define DP_MSG_SET_METADATA_INT_FIELD_FRAMERATE 2 #define DP_MSG_SET_METADATA_INT_FIELD_FRAME_COUNT 3 +#define DP_MSG_SET_METADATA_INT_NUM_FIELD 4 +#define DP_MSG_SET_METADATA_INT_ALL_FIELD \ + DP_MSG_SET_METADATA_INT_FIELD_DPIX, DP_MSG_SET_METADATA_INT_FIELD_DPIY, \ + DP_MSG_SET_METADATA_INT_FIELD_FRAMERATE, \ + DP_MSG_SET_METADATA_INT_FIELD_FRAME_COUNT + const char *DP_msg_set_metadata_int_field_variant_name(unsigned int value); typedef struct DP_MsgSetMetadataInt DP_MsgSetMetadataInt; @@ -2021,8 +2154,15 @@ int32_t DP_msg_set_metadata_int_value(const DP_MsgSetMetadataInt *msmi); #define DP_MSG_LAYER_TREE_CREATE_FLAGS_GROUP 0x1 #define DP_MSG_LAYER_TREE_CREATE_FLAGS_INTO 0x2 +#define DP_MSG_LAYER_TREE_CREATE_NUM_FLAGS 2 +#define DP_MSG_LAYER_TREE_CREATE_ALL_FLAGS \ + DP_MSG_LAYER_TREE_CREATE_FLAGS_GROUP, DP_MSG_LAYER_TREE_CREATE_FLAGS_INTO + const char *DP_msg_layer_tree_create_flags_flag_name(unsigned int value); +#define DP_MSG_LAYER_TREE_CREATE_TITLE_MIN_LEN 0 +#define DP_MSG_LAYER_TREE_CREATE_TITLE_MAX_LEN 65524 + typedef struct DP_MsgLayerTreeCreate DP_MsgLayerTreeCreate; DP_Message *DP_msg_layer_tree_create_new(unsigned int context_id, uint16_t id, @@ -2159,8 +2299,15 @@ uint16_t DP_msg_layer_tree_delete_merge_to(const DP_MsgLayerTreeDelete *mltd); #define DP_MSG_TRANSFORM_REGION_MODE_NEAREST 0 #define DP_MSG_TRANSFORM_REGION_MODE_BILINEAR 1 +#define DP_MSG_TRANSFORM_REGION_NUM_MODE 2 +#define DP_MSG_TRANSFORM_REGION_ALL_MODE \ + DP_MSG_TRANSFORM_REGION_MODE_NEAREST, DP_MSG_TRANSFORM_REGION_MODE_BILINEAR + const char *DP_msg_transform_region_mode_variant_name(unsigned int value); +#define DP_MSG_TRANSFORM_REGION_MASK_MIN_SIZE 0 +#define DP_MSG_TRANSFORM_REGION_MASK_MAX_SIZE 65482 + typedef struct DP_MsgTransformRegion DP_MsgTransformRegion; DP_Message *DP_msg_transform_region_new( @@ -2227,6 +2374,9 @@ size_t DP_msg_transform_region_mask_size(const DP_MsgTransformRegion *mtr); #define DP_MSG_TRACK_CREATE_STATIC_LENGTH 6 +#define DP_MSG_TRACK_CREATE_TITLE_MIN_LEN 0 +#define DP_MSG_TRACK_CREATE_TITLE_MAX_LEN 65529 + typedef struct DP_MsgTrackCreate DP_MsgTrackCreate; DP_Message *DP_msg_track_create_new(unsigned int context_id, uint16_t id, @@ -2262,6 +2412,9 @@ size_t DP_msg_track_create_title_len(const DP_MsgTrackCreate *mtc); #define DP_MSG_TRACK_RETITLE_STATIC_LENGTH 2 +#define DP_MSG_TRACK_RETITLE_TITLE_MIN_LEN 0 +#define DP_MSG_TRACK_RETITLE_TITLE_MAX_LEN 65533 + typedef struct DP_MsgTrackRetitle DP_MsgTrackRetitle; DP_Message *DP_msg_track_retitle_new(unsigned int context_id, uint16_t id, @@ -2319,6 +2472,9 @@ uint16_t DP_msg_track_delete_id(const DP_MsgTrackDelete *mtd); #define DP_MSG_TRACK_ORDER_STATIC_LENGTH 0 +#define DP_MSG_TRACK_ORDER_TRACKS_MIN_COUNT 0 +#define DP_MSG_TRACK_ORDER_TRACKS_MAX_COUNT 32767 + typedef struct DP_MsgTrackOrder DP_MsgTrackOrder; DP_Message *DP_msg_track_order_new(unsigned int context_id, @@ -2360,6 +2516,10 @@ int DP_msg_track_order_tracks_count(const DP_MsgTrackOrder *mto); #define DP_MSG_KEY_FRAME_SET_SOURCE_LAYER 0 #define DP_MSG_KEY_FRAME_SET_SOURCE_KEY_FRAME 1 +#define DP_MSG_KEY_FRAME_SET_NUM_SOURCE 2 +#define DP_MSG_KEY_FRAME_SET_ALL_SOURCE \ + DP_MSG_KEY_FRAME_SET_SOURCE_LAYER, DP_MSG_KEY_FRAME_SET_SOURCE_KEY_FRAME + const char *DP_msg_key_frame_set_source_variant_name(unsigned int value); typedef struct DP_MsgKeyFrameSet DP_MsgKeyFrameSet; @@ -2396,6 +2556,9 @@ uint8_t DP_msg_key_frame_set_source(const DP_MsgKeyFrameSet *mkfs); #define DP_MSG_KEY_FRAME_RETITLE_STATIC_LENGTH 4 +#define DP_MSG_KEY_FRAME_RETITLE_TITLE_MIN_LEN 0 +#define DP_MSG_KEY_FRAME_RETITLE_TITLE_MAX_LEN 65531 + typedef struct DP_MsgKeyFrameRetitle DP_MsgKeyFrameRetitle; DP_Message *DP_msg_key_frame_retitle_new(unsigned int context_id, @@ -2447,6 +2610,9 @@ size_t DP_msg_key_frame_retitle_title_len(const DP_MsgKeyFrameRetitle *mkfr); #define DP_MSG_KEY_FRAME_LAYER_ATTRIBUTES_STATIC_LENGTH 4 +#define DP_MSG_KEY_FRAME_LAYER_ATTRIBUTES_LAYERS_MIN_COUNT 0 +#define DP_MSG_KEY_FRAME_LAYER_ATTRIBUTES_LAYERS_MAX_COUNT 32765 + typedef struct DP_MsgKeyFrameLayerAttributes DP_MsgKeyFrameLayerAttributes; DP_Message *DP_msg_key_frame_layer_attributes_new( diff --git a/src/drawdance/libmsg/test/read_write_roundtrip.c b/src/drawdance/libmsg/test/read_write_roundtrip.c index a262154d6d..9501ead865 100644 --- a/src/drawdance/libmsg/test/read_write_roundtrip.c +++ b/src/drawdance/libmsg/test/read_write_roundtrip.c @@ -19,154 +19,1013 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include #include #include #include #include +#include #include +#include #include #include +#include #include -static void write_message_binary(TEST_PARAMS, void *writer, DP_Message *msg) +static DP_BinaryWriter *open_binary_writer(TEST_PARAMS, const char *path) { - OK(DP_binary_writer_write_message(writer, msg), "wrote message to binary"); + DP_Output *bo = DP_file_output_new_from_path(path); + FATAL(NOT_NULL_OK(bo, "got binary output for %s", path)); + DP_BinaryWriter *bw = DP_binary_writer_new(bo); + FATAL(NOT_NULL_OK(bw, "got binary writer for %s", path)); + return bw; } -static void write_message_text(TEST_PARAMS, void *writer, DP_Message *msg) +static DP_TextWriter *open_text_writer(TEST_PARAMS, const char *path) { - OK(DP_message_write_text(msg, writer), "wrote message to text"); + DP_Output *bo = DP_file_output_new_from_path(path); + FATAL(NOT_NULL_OK(bo, "got text output for %s", path)); + DP_TextWriter *tw = DP_text_writer_new(bo); + FATAL(NOT_NULL_OK(tw, "got text writer for %s", path)); + return tw; } -static void read_write_binary(TEST_PARAMS, DP_BinaryReader *reader, - void (*write_message)(TEST_PARAMS, void *, - DP_Message *), - void *writer) +static DP_BinaryReader *open_binary_reader(TEST_PARAMS, const char *path) { - while (true) { - DP_Message *msg; - DP_BinaryReaderResult result = - DP_binary_reader_read_message(reader, &msg); - OK(result == DP_BINARY_READER_SUCCESS - || result == DP_BINARY_READER_INPUT_END, - "binary read without error"); + DP_Input *bi = DP_file_input_new_from_path(path); + FATAL(NOT_NULL_OK(bi, "got binary input for %s", path)); + DP_BinaryReader *br = DP_binary_reader_new(bi); + FATAL(NOT_NULL_OK(br, "got binary reader for %s", path)); + return br; +} - if (result == DP_BINARY_READER_SUCCESS) { - write_message(TEST_ARGS, writer, msg); - DP_message_decref(msg); - } - else if (result == DP_BINARY_READER_INPUT_END) { - break; - } - else if (result == DP_BINARY_READER_ERROR_PARSE) { - DIAG("Parse error: %s", DP_error()); - } - else if (result == DP_BINARY_READER_ERROR_INPUT) { - DIAG("Input error: %s", DP_error()); - break; - } - else { - DIAG("Unknown binary reader result %d", (int)result); - break; +static DP_TextReader *open_text_reader(TEST_PARAMS, const char *path) +{ + DP_Input *ti = DP_file_input_new_from_path(path); + FATAL(NOT_NULL_OK(ti, "got text input for %s", path)); + DP_TextReader *tr = DP_text_reader_new(ti); + FATAL(NOT_NULL_OK(tr, "got text reader for %s", path)); + return tr; +} + +static void write_header(TEST_PARAMS, DP_BinaryWriter *bw, DP_TextWriter *tw, + JSON_Object *header) +{ + OK(DP_binary_writer_write_header(bw, header), "wrote binary header"); + OK(DP_text_writer_write_header(tw, header), "wrote text header"); +} + +static void write_initial_header(TEST_PARAMS, DP_BinaryWriter *bw, + DP_TextWriter *tw) +{ + JSON_Value *header_value = json_value_init_object(); + JSON_Object *header = json_value_get_object(header_value); + json_object_set_string(header, "version", DP_PROTOCOL_VERSION); + json_object_set_string(header, "writer", "read_write_roundtrip"); + json_object_set_string(header, "type", "recording"); + write_header(TEST_ARGS, bw, tw, header); + json_value_free(header_value); +} + +static void write_message_binary(TEST_PARAMS, DP_Message *msg, + DP_BinaryWriter *bw) +{ + OK(DP_binary_writer_write_message(bw, msg), "wrote message to binary"); +} + +static void write_message_text(TEST_PARAMS, DP_Message *msg, DP_TextWriter *tw) +{ + OK(DP_message_write_text(msg, tw), "wrote message to text"); +} + + +static bool random_bool(void) +{ + return rand() % 2 == 0; +} + +static uint32_t random_uint32(void) +{ + unsigned char bytes[] = { + DP_int_to_uchar(rand() & 0xff), + DP_int_to_uchar(rand() & 0xff), + DP_int_to_uchar(rand() & 0xff), + DP_int_to_uchar(rand() & 0xff), + }; + return DP_read_littleendian_uint32(bytes); +} + +static uint16_t random_uint16(void) +{ + return DP_uint32_to_uint16(random_uint32() & (uint32_t)0xffffu); +} + +static uint8_t random_uint8(void) +{ + return DP_uint32_to_uint8(random_uint32() & (uint32_t)0xffu); +} + +static int8_t random_int8(void) +{ + return DP_uint8_to_int8(random_uint8()); +} + +static int32_t random_int32(void) +{ + return DP_uint32_to_int32(random_uint32()); +} + +static int int_between(int min_inclusive, int max_inclusive) +{ + DP_ASSERT(min_inclusive <= max_inclusive); + DP_ASSERT(min_inclusive >= 0); + return min_inclusive + + DP_uint32_to_int( + random_uint32() + % DP_int_to_uint32(max_inclusive - min_inclusive + 1)); +} + +static size_t size_between(size_t min_inclusive, size_t max_inclusive) +{ + DP_ASSERT(min_inclusive <= max_inclusive); + DP_ASSERT(max_inclusive <= UINT32_MAX); + return min_inclusive + + DP_uint32_to_size( + random_uint32() + % DP_size_to_uint32(max_inclusive - min_inclusive + (size_t)1)); +} + +static unsigned int generate_context_id(void) +{ + return random_uint8(); +} + +static uint8_t generate_blend_mode(void) +{ + int mode = int_between(0, DP_BLEND_MODE_LAST_EXCEPT_REPLACE); + if (mode == DP_BLEND_MODE_LAST_EXCEPT_REPLACE) { + return DP_BLEND_MODE_REPLACE; + } + else { + return DP_int_to_uint8(mode); + } +} + +static uint8_t generate_flags(const unsigned int *flag_list, int count) +{ + uint8_t flags = 0; + for (int i = 0; i < count; ++i) { + unsigned int flag = flag_list[i]; + DP_ASSERT(flag < UINT8_MAX); + if (random_bool()) { + flags |= DP_uint_to_uint8(flag); } } + return flags; } -static void binary_to_binary(TEST_PARAMS) +static uint8_t generate_variant(const unsigned int *variant_list, int count) { - const char *key = T->test->user; - char *in_path = DP_format("test/data/recordings/%s.dprec", key); - char *out_path = - DP_format("test/tmp/read_binary_write_binary%s.dprec", key); + unsigned int variant = variant_list[int_between(0, count - 1)]; + DP_ASSERT(variant <= UINT8_MAX); + return DP_uint_to_uint8(variant); +} - DP_Input *input = DP_file_input_new_from_path(in_path); - FATAL(NOT_NULL_OK(input, "got input for %s", in_path)); +static char *generate_string(size_t length, size_t *out_length) +{ + char *string = DP_malloc(length + 1); + for (size_t i = 0; i < length; ++i) { + // NUL can't appear in any strings. Carriage return doesn't round-trip + // correctly in text mode, which is inconsequential in practice, but of + // course causes these tests to fail. So we exclude it. + char c; + do { + c = DP_uint8_to_char(random_uint8()); + } while (c == '\0' || c == '\r'); + string[i] = c; + } + string[length] = '\0'; + *out_length = length; + return string; +} - DP_BinaryReader *reader = DP_binary_reader_new(input); - FATAL(NOT_NULL_OK(reader, "got binary reader for %s", in_path)); +static void generate_bytes(size_t size, unsigned char *out, + DP_UNUSED void *user) +{ + for (size_t i = 0; i < size; ++i) { + out[i] = random_uint8(); + } +} - DP_Output *output = DP_file_output_new_from_path(out_path); - FATAL(NOT_NULL_OK(reader, "got output for %s", out_path)); +static void generate_uint8s(int count, uint8_t *out, DP_UNUSED void *user) +{ + for (int i = 0; i < count; ++i) { + out[i] = random_uint8(); + } +} - DP_BinaryWriter *writer = DP_binary_writer_new(output); - FATAL(NOT_NULL_OK(writer, "got binary writer for %s", out_path)); +static void generate_uint16s(int count, uint16_t *out, DP_UNUSED void *user) +{ + for (int i = 0; i < count; ++i) { + out[i] = random_uint16(); + } +} - JSON_Object *header = DP_binary_reader_header(reader); - if (NOT_NULL_OK(header, "got binary reader header")) { - OK(DP_binary_writer_write_header(writer, header), "wrote header"); +static void generate_classic_dabs(int count, DP_ClassicDab *out, + DP_UNUSED void *user) +{ + for (int i = 0; i < count; ++i) { + DP_classic_dab_init(out, i, random_int8(), random_int8(), + random_uint16(), random_uint8(), random_uint8()); } +} - read_write_binary(TEST_ARGS, reader, write_message_binary, writer); +static void generate_pixel_dabs(int count, DP_PixelDab *out, + DP_UNUSED void *user) +{ + for (int i = 0; i < count; ++i) { + DP_pixel_dab_init(out, i, random_int8(), random_int8(), random_uint8(), + random_uint8()); + } +} - DP_binary_writer_free(writer); - DP_binary_reader_free(reader); +static void generate_mypaint_dabs(int count, DP_MyPaintDab *out, + DP_UNUSED void *user) +{ + for (int i = 0; i < count; ++i) { + DP_mypaint_dab_init(out, i, random_int8(), random_int8(), + random_uint16(), random_uint8(), random_uint8(), + random_uint8(), random_uint8()); + } +} - FILE_EQ_OK(out_path, in_path, "binary output equal"); +static DP_Message *generate_server_command(void) +{ + size_t message_len; + char *message = + generate_string(size_between(DP_MSG_SERVER_COMMAND_MSG_MIN_LEN, + DP_MSG_SERVER_COMMAND_MSG_MAX_LEN), + &message_len); + DP_Message *msg = + DP_msg_server_command_new(generate_context_id(), message, message_len); + DP_free(message); + return msg; +} - DP_free(out_path); - DP_free(in_path); +static DP_Message *generate_ping(void) +{ + return DP_msg_ping_new(generate_context_id(), random_bool()); } +static DP_Message *generate_disconnect(void) +{ + size_t message_len; + char *message = + generate_string(size_between(DP_MSG_DISCONNECT_MESSAGE_MIN_LEN, + DP_MSG_DISCONNECT_MESSAGE_MAX_LEN), + &message_len); + DP_Message *msg = DP_msg_disconnect_new( + generate_context_id(), + generate_variant((unsigned int[]){DP_MSG_DISCONNECT_ALL_REASON}, + DP_MSG_DISCONNECT_NUM_REASON), + message, message_len); + DP_free(message); + return msg; +} -static void binary_to_text(TEST_PARAMS) +static DP_Message *generate_join(void) { - const char *key = T->test->user; - char *in_path = DP_format("test/data/recordings/%s.dprec", key); - char *out_path = DP_format("test/tmp/read_binary_write_text_%s.dprec", key); - char *expected_path = DP_format("test/data/recordings/%s.dptxt", key); + size_t name_len; + char *name = generate_string( + size_between(DP_MSG_JOIN_NAME_MIN_LEN, DP_MSG_JOIN_NAME_MAX_LEN), + &name_len); + size_t avatar_size = size_between( + DP_MSG_JOIN_AVATAR_MIN_SIZE, + DP_MESSAGE_MAX_PAYLOAD_LENGTH - DP_MSG_JOIN_STATIC_LENGTH - name_len); + DP_Message *msg = + DP_msg_join_new(generate_context_id(), + generate_flags((unsigned int[]){DP_MSG_JOIN_ALL_FLAGS}, + DP_MSG_JOIN_NUM_FLAGS), + name, name_len, generate_bytes, avatar_size, NULL); + DP_free(name); + return msg; +} - DP_Input *input = DP_file_input_new_from_path(in_path); - FATAL(NOT_NULL_OK(input, "got input for %s", in_path)); +static DP_Message *generate_leave(void) +{ + return DP_msg_leave_new(generate_context_id()); +} - DP_BinaryReader *reader = DP_binary_reader_new(input); - FATAL(NOT_NULL_OK(reader, "got binary reader for %s", in_path)); +static DP_Message *generate_session_owner(void) +{ + return DP_msg_session_owner_new( + generate_context_id(), generate_uint8s, + int_between(DP_MSG_SESSION_OWNER_USERS_MIN_COUNT, + DP_MSG_SESSION_OWNER_USERS_MAX_COUNT), + NULL); +} - DP_Output *output = DP_file_output_new_from_path(out_path); - FATAL(NOT_NULL_OK(reader, "got output for %s", out_path)); +static DP_Message *generate_trusted_users(void) +{ + return DP_msg_trusted_users_new( + generate_context_id(), generate_uint8s, + int_between(DP_MSG_TRUSTED_USERS_USERS_MIN_COUNT, + DP_MSG_TRUSTED_USERS_USERS_MAX_COUNT), + NULL); +} - DP_TextWriter *writer = DP_text_writer_new(output); - FATAL(NOT_NULL_OK(writer, "got text writer for %s", out_path)); +static DP_Message *generate_soft_reset(void) +{ + return DP_msg_soft_reset_new(generate_context_id()); +} - JSON_Object *header = DP_binary_reader_header(reader); - if (NOT_NULL_OK(header, "got binary reader header")) { - OK(DP_text_writer_write_header(writer, header), "wrote header"); - } +static DP_Message *generate_private_chat(void) +{ + size_t message_len; + char *message = + generate_string(size_between(DP_MSG_PRIVATE_CHAT_MESSAGE_MIN_LEN, + DP_MSG_PRIVATE_CHAT_MESSAGE_MAX_LEN), + &message_len); + DP_Message *msg = + DP_msg_private_chat_new(generate_context_id(), random_uint8(), + random_uint8(), message, message_len); + DP_free(message); + return msg; +} - read_write_binary(TEST_ARGS, reader, write_message_text, writer); +static DP_Message *generate_interval(void) +{ + return DP_msg_interval_new(generate_context_id(), random_uint16()); +} - DP_text_writer_free(writer); - DP_binary_reader_free(reader); +static DP_Message *generate_laser_trail(void) +{ + return DP_msg_laser_trail_new(generate_context_id(), random_uint32(), + random_uint8()); +} - FILE_EQ_OK(out_path, expected_path, "text output equal"); +static DP_Message *generate_move_pointer(void) +{ + return DP_msg_move_pointer_new(generate_context_id(), random_int32(), + random_int32()); +} - DP_free(expected_path); - DP_free(out_path); - DP_free(in_path); +static DP_Message *generate_marker(void) +{ + size_t text_len; + char *text = generate_string( + size_between(DP_MSG_MARKER_TEXT_MIN_LEN, DP_MSG_MARKER_TEXT_MAX_LEN), + &text_len); + DP_Message *msg = DP_msg_marker_new(generate_context_id(), text, text_len); + DP_free(text); + return msg; } +static DP_Message *generate_user_acl(void) +{ + return DP_msg_user_acl_new(generate_context_id(), generate_uint8s, + int_between(DP_MSG_USER_ACL_USERS_MIN_COUNT, + DP_MSG_USER_ACL_USERS_MAX_COUNT), + NULL); +} -static void register_tests(REGISTER_PARAMS) +static DP_Message *generate_layer_acl(void) +{ + return DP_msg_layer_acl_new( + generate_context_id(), random_uint16(), random_uint8(), generate_uint8s, + int_between(DP_MSG_LAYER_ACL_EXCLUSIVE_MIN_COUNT, + DP_MSG_LAYER_ACL_EXCLUSIVE_MAX_COUNT), + NULL); +} + +static DP_Message *generate_feature_access_levels(void) +{ + return DP_msg_feature_access_levels_new( + generate_context_id(), generate_uint8s, + int_between(DP_MSG_FEATURE_ACCESS_LEVELS_FEATURE_TIERS_MIN_COUNT, + DP_MSG_FEATURE_ACCESS_LEVELS_FEATURE_TIERS_MAX_COUNT), + NULL); +} + +static DP_Message *generate_default_layer(void) +{ + return DP_msg_default_layer_new(generate_context_id(), random_uint16()); +} + +static DP_Message *generate_filtered(void) +{ + return DP_msg_filtered_new(generate_context_id(), generate_bytes, + size_between(DP_MSG_FILTERED_MESSAGE_MIN_SIZE, + DP_MSG_FILTERED_MESSAGE_MAX_SIZE), + NULL); +} + +static DP_Message *generate_undo_depth(void) +{ + return DP_msg_undo_depth_new(generate_context_id(), random_uint8()); +} + +static DP_Message *generate_data(void) +{ + return DP_msg_data_new( + generate_context_id(), + generate_variant((unsigned int[]){DP_MSG_DATA_ALL_TYPE}, + DP_MSG_DATA_NUM_TYPE), + random_uint8(), generate_bytes, + size_between(DP_MSG_DATA_BODY_MIN_SIZE, DP_MSG_DATA_BODY_MAX_SIZE), + NULL); +} + +static DP_Message *generate_local_change(void) +{ + return DP_msg_local_change_new( + generate_context_id(), + generate_variant((unsigned int[]){DP_MSG_LOCAL_CHANGE_ALL_TYPE}, + DP_MSG_LOCAL_CHANGE_NUM_TYPE), + generate_bytes, + size_between(DP_MSG_LOCAL_CHANGE_BODY_MIN_SIZE, + DP_MSG_LOCAL_CHANGE_BODY_MAX_SIZE), + NULL); +} + +static DP_Message *generate_undo_point(void) +{ + return DP_msg_undo_point_new(generate_context_id()); +} + +static DP_Message *generate_canvas_resize(void) +{ + return DP_msg_canvas_resize_new(generate_context_id(), random_int32(), + random_int32(), random_int32(), + random_int32()); +} + +static DP_Message *generate_layer_create(void) +{ + size_t title_len; + char *title = + generate_string(size_between(DP_MSG_LAYER_CREATE_TITLE_MIN_LEN, + DP_MSG_LAYER_CREATE_TITLE_MAX_LEN), + &title_len); + DP_Message *msg = DP_msg_layer_create_new( + generate_context_id(), random_uint16(), random_uint16(), + random_uint32(), + generate_flags((unsigned int[]){DP_MSG_LAYER_CREATE_ALL_FLAGS}, + DP_MSG_LAYER_CREATE_NUM_FLAGS), + title, title_len); + DP_free(title); + return msg; +} + +static DP_Message *generate_layer_attributes(void) +{ + return DP_msg_layer_attributes_new( + generate_context_id(), random_uint16(), random_uint8(), + generate_flags((unsigned int[]){DP_MSG_LAYER_ATTRIBUTES_ALL_FLAGS}, + DP_MSG_LAYER_ATTRIBUTES_NUM_FLAGS), + random_uint8(), generate_blend_mode()); +} + +static DP_Message *generate_layer_retitle(void) +{ + size_t title_len; + char *title = + generate_string(size_between(DP_MSG_LAYER_RETITLE_TITLE_MIN_LEN, + DP_MSG_LAYER_RETITLE_TITLE_MAX_LEN), + &title_len); + DP_Message *msg = DP_msg_layer_retitle_new( + generate_context_id(), random_uint16(), title, title_len); + DP_free(title); + return msg; +} + +static DP_Message *generate_layer_order(void) +{ + return DP_msg_layer_order_new( + generate_context_id(), generate_uint16s, + int_between(DP_MSG_LAYER_ORDER_LAYERS_MIN_COUNT, + DP_MSG_LAYER_ORDER_LAYERS_MAX_COUNT), + NULL); +} + +static DP_Message *generate_layer_delete(void) +{ + return DP_msg_layer_delete_new(generate_context_id(), random_uint16(), + random_bool()); +} + +static DP_Message *generate_layer_visibility(void) +{ + return DP_msg_layer_visibility_new(generate_context_id(), random_uint16(), + random_bool()); +} + +static DP_Message *generate_put_image(void) +{ + return DP_msg_put_image_new(generate_context_id(), random_uint16(), + generate_blend_mode(), random_uint32(), + random_uint32(), random_uint32(), + random_uint32(), generate_bytes, + size_between(DP_MSG_PUT_IMAGE_IMAGE_MIN_SIZE, + DP_MSG_PUT_IMAGE_IMAGE_MAX_SIZE), + NULL); +} + +static DP_Message *generate_fill_rect(void) +{ + return DP_msg_fill_rect_new(generate_context_id(), random_uint16(), + generate_blend_mode(), random_uint32(), + random_uint32(), random_uint32(), + random_uint32(), random_uint32()); +} + +static DP_Message *generate_pen_up(void) +{ + return DP_msg_pen_up_new(generate_context_id()); +} + +static DP_Message *generate_annotation_create(void) +{ + return DP_msg_annotation_create_new(generate_context_id(), random_uint16(), + random_int32(), random_int32(), + random_uint16(), random_uint16()); +} + +static DP_Message *generate_annotation_reshape(void) +{ + return DP_msg_annotation_reshape_new(generate_context_id(), random_uint16(), + random_int32(), random_int32(), + random_uint16(), random_uint16()); +} + +static DP_Message *generate_annotation_edit(void) +{ + size_t text_len; + char *text = + generate_string(size_between(DP_MSG_ANNOTATION_EDIT_TEXT_MIN_LEN, + DP_MSG_ANNOTATION_EDIT_TEXT_MAX_LEN), + &text_len); + DP_Message *msg = DP_msg_annotation_edit_new( + generate_context_id(), random_uint16(), random_uint32(), + generate_flags((unsigned int[]){DP_MSG_ANNOTATION_EDIT_ALL_FLAGS}, + DP_MSG_ANNOTATION_EDIT_NUM_FLAGS), + random_uint8(), text, text_len); + DP_free(text); + return msg; +} + +static DP_Message *generate_annotation_delete(void) +{ + return DP_msg_annotation_delete_new(generate_context_id(), random_uint16()); +} + +static DP_Message *generate_move_region(void) +{ + return DP_msg_move_region_new( + generate_context_id(), random_uint16(), random_int32(), random_int32(), + random_int32(), random_int32(), random_int32(), random_int32(), + random_int32(), random_int32(), random_int32(), random_int32(), + random_int32(), random_int32(), generate_bytes, + size_between(DP_MSG_MOVE_REGION_MASK_MIN_SIZE, + DP_MSG_MOVE_REGION_MASK_MAX_SIZE), + NULL); +} + +static DP_Message *generate_put_tile(void) +{ + return DP_msg_put_tile_new(generate_context_id(), random_uint16(), + random_uint8(), random_uint16(), random_uint16(), + random_uint16(), generate_bytes, + size_between(DP_MSG_PUT_TILE_IMAGE_MIN_SIZE, + DP_MSG_PUT_TILE_IMAGE_MAX_SIZE), + NULL); +} + +static DP_Message *generate_canvas_background(void) +{ + return DP_msg_canvas_background_new( + generate_context_id(), generate_bytes, + size_between(DP_MSG_CANVAS_BACKGROUND_IMAGE_MIN_SIZE, + DP_MSG_CANVAS_BACKGROUND_IMAGE_MAX_SIZE), + NULL); +} + +static DP_Message *generate_draw_dabs_classic(void) +{ + return DP_msg_draw_dabs_classic_new( + generate_context_id(), random_uint16(), random_int32(), random_int32(), + random_uint32(), generate_blend_mode(), generate_classic_dabs, + int_between(DP_MSG_DRAW_DABS_CLASSIC_DABS_MIN_COUNT, + DP_MSG_DRAW_DABS_CLASSIC_DABS_MAX_COUNT), + NULL); +} + +static DP_Message *generate_draw_dabs_pixel(void) +{ + return DP_msg_draw_dabs_pixel_new( + generate_context_id(), random_uint16(), random_int32(), random_int32(), + random_uint32(), generate_blend_mode(), generate_pixel_dabs, + int_between(DP_MSG_DRAW_DABS_PIXEL_DABS_MIN_COUNT, + DP_MSG_DRAW_DABS_PIXEL_DABS_MAX_COUNT), + NULL); +} + +static DP_Message *generate_draw_dabs_pixel_square(void) +{ + return DP_msg_draw_dabs_pixel_square_new( + generate_context_id(), random_uint16(), random_int32(), random_int32(), + random_uint32(), generate_blend_mode(), generate_pixel_dabs, + int_between(DP_MSG_DRAW_DABS_PIXEL_DABS_MIN_COUNT, + DP_MSG_DRAW_DABS_PIXEL_DABS_MAX_COUNT), + NULL); +} + +static DP_Message *generate_draw_dabs_mypaint(void) +{ + return DP_msg_draw_dabs_mypaint_new( + generate_context_id(), random_uint16(), random_int32(), random_int32(), + random_uint32(), random_uint8(), random_uint8(), random_uint8(), + random_uint8(), generate_mypaint_dabs, + int_between(DP_MSG_DRAW_DABS_MYPAINT_DABS_MIN_COUNT, + DP_MSG_DRAW_DABS_MYPAINT_DABS_MAX_COUNT), + NULL); +} + +static DP_Message *generate_move_rect(void) +{ + return DP_msg_move_rect_new(generate_context_id(), random_uint16(), + random_uint16(), random_int32(), random_int32(), + random_int32(), random_int32(), random_int32(), + random_int32(), generate_bytes, + size_between(DP_MSG_MOVE_RECT_MASK_MIN_SIZE, + DP_MSG_MOVE_REGION_MASK_MAX_SIZE), + NULL); +} + +static DP_Message *generate_set_metadata_int(void) +{ + return DP_msg_set_metadata_int_new( + generate_context_id(), + generate_variant((unsigned int[]){DP_MSG_SET_METADATA_INT_ALL_FIELD}, + DP_MSG_SET_METADATA_INT_NUM_FIELD), + random_int32()); +} + +static DP_Message *generate_layer_tree_create(void) +{ + size_t title_len; + char *title = + generate_string(size_between(DP_MSG_LAYER_TREE_CREATE_TITLE_MIN_LEN, + DP_MSG_LAYER_TREE_CREATE_TITLE_MAX_LEN), + &title_len); + DP_Message *msg = DP_msg_layer_tree_create_new( + generate_context_id(), random_uint16(), random_uint16(), + random_uint16(), random_uint32(), + generate_flags((unsigned int[]){DP_MSG_LAYER_TREE_CREATE_ALL_FLAGS}, + DP_MSG_LAYER_TREE_CREATE_NUM_FLAGS), + title, title_len); + DP_free(title); + return msg; +} + +static DP_Message *generate_layer_tree_move(void) +{ + return DP_msg_layer_tree_move_new(generate_context_id(), random_uint16(), + random_uint16(), random_uint16()); +} + +static DP_Message *generate_layer_tree_delete(void) +{ + return DP_msg_layer_tree_delete_new(generate_context_id(), random_uint16(), + random_uint16()); +} + +static DP_Message *generate_transform_region(void) +{ + return DP_msg_transform_region_new( + generate_context_id(), random_uint16(), random_uint16(), random_int32(), + random_int32(), random_int32(), random_int32(), random_int32(), + random_int32(), random_int32(), random_int32(), random_int32(), + random_int32(), random_int32(), random_int32(), + generate_variant((unsigned int[]){DP_MSG_TRANSFORM_REGION_ALL_MODE}, + DP_MSG_TRANSFORM_REGION_NUM_MODE), + generate_bytes, + size_between(DP_MSG_TRANSFORM_REGION_MASK_MIN_SIZE, + DP_MSG_TRANSFORM_REGION_MASK_MAX_SIZE), + NULL); +} + +static DP_Message *generate_track_create(void) +{ + size_t title_len; + char *title = + generate_string(size_between(DP_MSG_TRACK_CREATE_TITLE_MIN_LEN, + DP_MSG_TRACK_CREATE_TITLE_MAX_LEN), + &title_len); + DP_Message *msg = DP_msg_track_create_new( + generate_context_id(), random_uint16(), random_uint16(), + random_uint16(), title, title_len); + DP_free(title); + return msg; +} + +static DP_Message *generate_track_retitle(void) +{ + size_t title_len; + char *title = + generate_string(size_between(DP_MSG_TRACK_RETITLE_TITLE_MIN_LEN, + DP_MSG_TRACK_RETITLE_TITLE_MAX_LEN), + &title_len); + DP_Message *msg = DP_msg_track_retitle_new( + generate_context_id(), random_uint16(), title, title_len); + DP_free(title); + return msg; +} + +static DP_Message *generate_track_delete(void) { - const char *keys[] = { - "blank", "rect", "resize", "stroke", "transform", "drawdabs", + return DP_msg_track_delete_new(generate_context_id(), random_uint16()); +} + +static DP_Message *generate_track_order(void) +{ + return DP_msg_track_order_new( + generate_context_id(), generate_uint16s, + int_between(DP_MSG_TRACK_ORDER_TRACKS_MIN_COUNT, + DP_MSG_TRACK_ORDER_TRACKS_MAX_COUNT), + NULL); +} + +static DP_Message *generate_key_frame_set(void) +{ + return DP_msg_key_frame_set_new( + generate_context_id(), random_uint16(), random_uint16(), + random_uint16(), random_uint16(), + generate_variant((unsigned int[]){DP_MSG_KEY_FRAME_SET_ALL_SOURCE}, + DP_MSG_KEY_FRAME_SET_NUM_SOURCE)); +} + +static DP_Message *generate_key_frame_retitle(void) +{ + size_t title_len; + char *title = + generate_string(size_between(DP_MSG_KEY_FRAME_RETITLE_TITLE_MIN_LEN, + DP_MSG_KEY_FRAME_RETITLE_TITLE_MAX_LEN), + &title_len); + DP_Message *msg = + DP_msg_key_frame_retitle_new(generate_context_id(), random_uint16(), + random_uint16(), title, title_len); + DP_free(title); + return msg; +} + +static DP_Message *generate_key_frame_layer_attributes(void) +{ + return DP_msg_key_frame_layer_attributes_new( + generate_context_id(), random_uint16(), random_uint16(), + generate_uint16s, + int_between(DP_MSG_KEY_FRAME_LAYER_ATTRIBUTES_LAYERS_MIN_COUNT, + DP_MSG_KEY_FRAME_LAYER_ATTRIBUTES_LAYERS_MAX_COUNT), + NULL); +} + +static DP_Message *generate_key_frame_delete(void) +{ + return DP_msg_key_frame_delete_new(generate_context_id(), random_uint16(), + random_uint16(), random_uint16(), + random_uint16()); +} + +static DP_Message *generate_undo(void) +{ + return DP_msg_undo_new(generate_context_id(), random_uint8(), + random_bool()); +} + + +typedef DP_Message *(*GenerateFn)(void); + +static void write_messages(TEST_PARAMS, DP_BinaryWriter *bw, DP_TextWriter *tw) +{ + GenerateFn fns[] = { + generate_server_command, + generate_disconnect, + generate_ping, + generate_join, + generate_leave, + generate_session_owner, + generate_trusted_users, + generate_soft_reset, + generate_private_chat, + generate_interval, + generate_laser_trail, + generate_move_pointer, + generate_marker, + generate_user_acl, + generate_layer_acl, + generate_feature_access_levels, + generate_default_layer, + generate_filtered, + generate_undo_depth, + generate_data, + generate_local_change, + generate_undo_point, + generate_canvas_resize, + generate_layer_create, + generate_layer_attributes, + generate_layer_retitle, + generate_layer_order, + generate_layer_delete, + generate_layer_visibility, + generate_put_image, + generate_fill_rect, + generate_pen_up, + generate_annotation_create, + generate_annotation_reshape, + generate_annotation_edit, + generate_annotation_delete, + generate_move_region, + generate_put_tile, + generate_canvas_background, + generate_draw_dabs_classic, + generate_draw_dabs_pixel, + generate_draw_dabs_pixel_square, + generate_draw_dabs_mypaint, + generate_move_rect, + generate_set_metadata_int, + generate_layer_tree_create, + generate_layer_tree_move, + generate_layer_tree_delete, + generate_transform_region, + generate_track_create, + generate_track_retitle, + generate_track_delete, + generate_track_order, + generate_key_frame_set, + generate_key_frame_retitle, + generate_key_frame_layer_attributes, + generate_key_frame_delete, + generate_undo, }; + int count = DP_ARRAY_LENGTH(fns); + for (int i = 0; i < count; ++i) { + DP_Message *msg = fns[i](); + write_message_binary(TEST_ARGS, msg, bw); + write_message_text(TEST_ARGS, msg, tw); + DP_message_decref(msg); + } +} - for (size_t i = 0; i < DP_ARRAY_LENGTH(keys); ++i) { - const char *key = keys[i]; - { - char *binary_name = DP_format("%s_binary", key); - DP_test_register(REGISTER_ARGS, binary_name, binary_to_binary, - (void *)key); - DP_free(binary_name); +static void write_initial_messages(TEST_PARAMS) +{ + DP_BinaryWriter *bw = + open_binary_writer(TEST_ARGS, "test/tmp/roundtrip_base.dprec"); + DP_TextWriter *tw = + open_text_writer(TEST_ARGS, "test/tmp/roundtrip_base.dptxt"); + write_initial_header(TEST_ARGS, bw, tw); + write_messages(TEST_ARGS, bw, tw); + DP_binary_writer_free(bw); + DP_text_writer_free(tw); +} + +static void read_binary_messages(TEST_PARAMS) +{ + DP_BinaryReader *br = + open_binary_reader(TEST_ARGS, "test/tmp/roundtrip_base.dprec"); + DP_BinaryWriter *bw = + open_binary_writer(TEST_ARGS, "test/tmp/roundtrip_from_dprec.dprec"); + DP_TextWriter *tw = + open_text_writer(TEST_ARGS, "test/tmp/roundtrip_from_dprec.dptxt"); + + write_header(TEST_ARGS, bw, tw, DP_binary_reader_header(br)); + + while (true) { + DP_Message *msg; + DP_BinaryReaderResult result = DP_binary_reader_read_message(br, &msg); + OK(result == DP_BINARY_READER_SUCCESS + || result == DP_BINARY_READER_INPUT_END, + "read binary message"); + if (result == DP_BINARY_READER_SUCCESS) { + write_message_binary(TEST_ARGS, msg, bw); + write_message_text(TEST_ARGS, msg, tw); + DP_message_decref(msg); } - { - char *text_name = DP_format("%s_text", key); - DP_test_register(REGISTER_ARGS, text_name, binary_to_text, - (void *)key); - DP_free(text_name); + else if (result == DP_BINARY_READER_INPUT_END) { + break; + } + else if (result == DP_BINARY_READER_ERROR_INPUT) { + DIAG("Binary reader input error %s", DP_error()); + break; + } + else if (result == DP_BINARY_READER_ERROR_PARSE) { + DIAG("Binary reader parse error %s", DP_error()); + break; + } + else { + DIAG("Binary reader unknown error %s", DP_error()); + break; } } + + DP_binary_writer_free(bw); + DP_text_writer_free(tw); + DP_binary_reader_free(br); +} + +static void read_text_messages(TEST_PARAMS) +{ + DP_TextReader *tr = + open_text_reader(TEST_ARGS, "test/tmp/roundtrip_base.dptxt"); + DP_BinaryWriter *bw = + open_binary_writer(TEST_ARGS, "test/tmp/roundtrip_from_dptxt.dprec"); + DP_TextWriter *tw = + open_text_writer(TEST_ARGS, "test/tmp/roundtrip_from_dptxt.dptxt"); + + bool healthy = true; + { + JSON_Value *header_value = json_value_init_object(); + JSON_Object *header = json_value_get_object(header_value); + while (healthy) { + const char *key, *value; + DP_TextReaderResult result = + DP_text_reader_read_header_field(tr, &key, &value); + healthy = OK(result == DP_TEXT_READER_SUCCESS + || result == DP_TEXT_READER_HEADER_END, + "read text header field"); + if (result == DP_TEXT_READER_SUCCESS) { + json_object_set_string(header, key, value); + } + else if (result == DP_TEXT_READER_HEADER_END) { + break; + } + else if (result == DP_TEXT_READER_ERROR_INPUT) { + DIAG("Text reader header input error %s", DP_error()); + } + else if (result == DP_TEXT_READER_ERROR_PARSE) { + DIAG("Text reader header parse error %s", DP_error()); + } + else { + DIAG("Text reader header unknown error %s", DP_error()); + } + } + write_header(TEST_ARGS, bw, tw, header); + json_value_free(header_value); + } + + while (healthy) { + DP_Message *msg; + DP_TextReaderResult result = DP_text_reader_read_message(tr, &msg); + healthy = OK(result == DP_TEXT_READER_SUCCESS + || result == DP_TEXT_READER_INPUT_END, + "read text message"); + if (result == DP_TEXT_READER_SUCCESS) { + write_message_binary(TEST_ARGS, msg, bw); + write_message_text(TEST_ARGS, msg, tw); + DP_message_decref(msg); + } + else if (result == DP_TEXT_READER_INPUT_END) { + break; + } + else if (result == DP_TEXT_READER_ERROR_INPUT) { + DIAG("Text reader input error %s", DP_error()); + } + else if (result == DP_TEXT_READER_ERROR_PARSE) { + DIAG("Text reader parse error %s", DP_error()); + } + else { + DIAG("Text reader unknown error %s", DP_error()); + } + } + + DP_binary_writer_free(bw); + DP_text_writer_free(tw); + DP_text_reader_free(tr); +} + +static void read_write_roundtrip(TEST_PARAMS) +{ + write_initial_messages(TEST_ARGS); + read_binary_messages(TEST_ARGS); + read_text_messages(TEST_ARGS); + FILE_EQ_OK("test/tmp/roundtrip_from_dprec.dprec", + "test/tmp/roundtrip_base.dprec", + "roundtrip from dprec to dprec"); + FILE_EQ_OK("test/tmp/roundtrip_from_dprec.dptxt", + "test/tmp/roundtrip_base.dptxt", + "roundtrip from dprec to dptxt"); + FILE_EQ_OK("test/tmp/roundtrip_from_dptxt.dprec", + "test/tmp/roundtrip_base.dprec", + "roundtrip from dptxt to dprec"); + FILE_EQ_OK("test/tmp/roundtrip_from_dptxt.dptxt", + "test/tmp/roundtrip_base.dptxt", + "roundtrip from dptxt to dptxt"); +} + + +static void register_tests(REGISTER_PARAMS) +{ + REGISTER_TEST(read_write_roundtrip); } int main(int argc, char **argv) diff --git a/src/drawdance/libtest/CMakeLists.txt b/src/drawdance/libtest/CMakeLists.txt index b4a618aafb..46f1bdef3e 100644 --- a/src/drawdance/libtest/CMakeLists.txt +++ b/src/drawdance/libtest/CMakeLists.txt @@ -7,7 +7,7 @@ target_sources(dptest PRIVATE ) target_include_directories(dptest INTERFACE "${CMAKE_CURRENT_LIST_DIR}/dptest") -target_link_libraries(dptest PRIVATE dpcommon) +target_link_libraries(dptest PUBLIC dpcommon) function(add_dptest_targets type lib) foreach(test_file IN LISTS ARGN) @@ -18,7 +18,7 @@ function(add_dptest_targets type lib) target_include_directories("${test_name}" PRIVATE "${PROJECT_SOURCE_DIR}/src/drawdance/libtest/dptest" ) - target_link_libraries("${test_name}" PRIVATE "dp${type}" "${lib}") + target_link_libraries("${test_name}" PUBLIC "dp${type}" "${lib}") add_test( NAME "${test_name}"