示例#1
0
文件: server_test.c 项目: tml/libot
static bool server_receive_fires_event_when_parent_cannot_be_found(char** msg) {
    ot_op* initial_op = ot_new_op();
    ot_insert(initial_op, "abc");

    ot_doc* doc = ot_new_doc();
    ot_doc_append(doc, &initial_op);

    ot_server* server = ot_new_server(send, event);
    ot_server_open(server, doc);

    const int NONEMPTY_HASH = 0xFF;
    ot_op* invalid_op = ot_new_op();
    ot_insert(invalid_op, "abc");
    memset(invalid_op->parent, NONEMPTY_HASH, 20);

    char* invalid_op_enc = ot_encode(invalid_op);
    ot_server_receive(server, invalid_op_enc);

    ot_op* dec = ot_new_op();
    ot_err err = ot_decode(dec, sent_msg);
    ASSERT_INT_EQUAL(OT_ERR_XFORM_FAILED, err, "Sent error was incorrect.",
                     msg);

    ot_free_op(dec);
    ot_free_op(invalid_op);
    ot_free_server(server);
    free(invalid_op_enc);
    return true;
}
示例#2
0
文件: server_test.c 项目: tml/libot
static bool server_receive_fires_event_when_xform_error_occurs(char** msg) {
    ot_op* initial_op = ot_new_op();
    ot_insert(initial_op, "abc");

    ot_doc* doc = ot_new_doc();
    ot_doc_append(doc, &initial_op);

    ot_server* server = ot_new_server(send, event);
    ot_server_open(server, doc);

    ot_op* invalid_op = ot_new_op();
    ot_skip(invalid_op, 1);

    char* invalid_op_enc = ot_encode(invalid_op);
    ot_server_receive(server, invalid_op_enc);

    ot_op* dec = ot_new_op();
    ot_err err = ot_decode(dec, sent_msg);
    ASSERT_INT_EQUAL(OT_ERR_XFORM_FAILED, err, "Sent error was incorrect.",
                     msg);

    ot_free_op(dec);
    ot_free_op(invalid_op);
    ot_free_server(server);
    free(invalid_op_enc);
    return true;
}
示例#3
0
static bool param_compose_test(ot_op* op1, ot_op* op2, ot_op* expected,
                               char** msg) {
    ot_op* actual = ot_compose(op1, op2);
    ot_free_op(op1);
    ot_free_op(op2);

    if (actual == NULL) {
        if (expected == NULL) {
            return true;
        } else {
            FAIL("Operations couldn't be composed.", msg);
        }
    }
    bool equal = ot_equal(expected, actual);
    char* expected_enc = ot_encode(expected);
    char* actual_enc = ot_encode(actual);
    ASSERT_CONDITION(equal, expected_enc, actual_enc,
                     "Composed operation wasn't correct.", msg);

    ot_free_op(expected);
    ot_free_op(actual);
    free(expected_enc);
    free(actual_enc);
    return true;
}
示例#4
0
static bool compose_returns_op_with_client_and_parent_of_first_op(char** msg) {
    const int NONZERO_INT = 1;
    const int NONEMPTY_PARENT = 0xFF;

    ot_op* op1 = ot_new_op();
    op1->client_id = NONZERO_INT;
    memset(op1->parent, NONEMPTY_PARENT, 20);

    ot_op* op2 = ot_new_op();

    ot_op* composed = ot_compose(op1, op2);
    if (composed == NULL) {
        FAIL("Operations couldn't be composed.", msg);
    }
    ASSERT_INT_EQUAL(op1->client_id, composed->client_id,
                     "The client ID of the composed operation wasn't equal to "
                     "the client ID of the first operation.",
                     msg);
    bool parents_equal = (memcmp(op1->parent, composed->parent, 20) == 0);
    if (!parents_equal) {
        FAIL("The parent of the composed operation wasn't equal to the parent "
             "of the first operation.",
             msg);
    }

    ot_free_op(op1);
    ot_free_op(op2);
    ot_free_op(composed);
    return true;
}
示例#5
0
文件: server_test.c 项目: tml/libot
static bool server_receive_when_empty_doc_is_opened(char** msg) {
    ot_server* server = ot_new_server(send, event);
    ot_doc* doc = ot_new_doc();
    ot_server_open(server, doc);

    ot_op* op = ot_new_op();
    ot_insert(op, "abc");

    char* op_enc = ot_encode(op);
    ot_server_receive(server, op_enc);

    ot_op* dec = ot_new_op();
    ot_err err = ot_decode(dec, sent_msg);
    ASSERT_INT_EQUAL(OT_ERR_NONE, err, "Unexpected sent error.", msg);
    ASSERT_OP_EQUAL(op, server->doc->composed, "Document state was incorrect.",
                    msg);

    ot_free_op(dec);
    ot_free_op(op);
    ot_free_server(server);
    free(op_enc);
    return true;
}
示例#6
0
文件: server_test.c 项目: tml/libot
static bool server_receive_fires_event_when_a_decode_error_occurs(char** msg) {
    ot_server* server = ot_new_server(send, event);
    char* invalid_msg = "not json";
    ot_server_receive(server, invalid_msg);

    ot_op* dec = ot_new_op();
    ot_err err = ot_decode(dec, sent_msg);
    ASSERT_INT_EQUAL(OT_ERR_INVALID_JSON, err, "Sent error was incorrect.",
                     msg);

    ot_free_op(dec);
    ot_free_server(server);
    return true;
}
示例#7
0
ot_op* ot_doc_compose_after(const ot_doc* doc, const char* after) {
    array history = doc->history;
    if (history.len == 0) {
        return NULL;
    }

    bool after_null = true;
    for (int i = 0; i < 20; ++i) {
        if (after[i] != 0) {
            after_null = false;
            break;
        }
    }

    bool found = false;
    size_t start = 0;
    ot_op* ops = (ot_op*)history.data;
    if (!after_null) {
        for (size_t i = history.len - 1; i < history.len; --i) {
            ot_op* op = ops + i;
            if (memcmp(op->hash, after, sizeof(char) * 20) == 0) {
                start = i + 1;
                found = true;
                break;
            }
        }

        if (!found) {
            return NULL;
        }
    }

    ot_op* composed = ot_dup_op(ops + start);
    ot_op* temp;
    for (size_t i = start + 1; i < history.len; ++i) {
        temp = ot_compose(composed, ops + i);
        ot_free_op(composed);
        composed = temp;
        if (composed == NULL) {
            return NULL;
        }
    }

    return composed;
}
示例#8
0
void ot_free_doc(ot_doc* doc) {
    // Free the components of every op in the document's history.
    ot_op* ops = doc->history.data;
    for (size_t i = 0; i < doc->history.len; ++i) {
        ot_op* op = ops + i;
        ot_comp* comps = op->comps.data;
        for (size_t j = 0; j < op->comps.len; ++j) {
            ot_free_comp(comps + j);
        }
        array_free(&op->comps);
    }

    // Free the history array, which frees the all of ops.
    array_free(&doc->history);

    // When the history length is less than 2, then the composed op is just
    // pointing to the first op in the history (which has already been freed).
    if (doc->history.len > 1) {
        ot_free_op(doc->composed);
    }

    free(doc);
}
示例#9
0
ot_err ot_doc_append(ot_doc* doc, ot_op** op) {
    if (doc->max_size > 0 && ot_size(*op) + doc->size > doc->max_size) {
        return OT_ERR_MAX_SIZE;
    }

    // Move the op into the document's history array.
    ot_op* head = array_append(&doc->history);
    memcpy(head, *op, sizeof(ot_op));

    size_t len = doc->history.len;
    if (len > 1) {
        ot_op* history = (ot_op*)doc->history.data;
        ot_op* prev = &history[len - 2];
        memcpy(head->parent, prev->hash, 20);
    } else {
        char zero[20] = { 0 };
        memcpy(head->parent, zero, 20);
    }

    // If we're appending the first op, then the composed state will simply be
    // the first op in the history. If we're appending the second op, then we
    // must ensure that the composed op still points to the first op in the
    // history in case its location changed after calling array_append (which
    // may have reallocated the array to a different location in memory).
    if (doc->history.len <= 2) {
        doc->composed = (ot_op*)doc->history.data;
    }

    // If we're appending any op after the first, then we must compose the new
    // op with the currently composed state to get the new composed state.
    if (doc->history.len > 1) {
        ot_op* new_composed = ot_compose(doc->composed, head);
        if (new_composed == NULL) {
            doc->history.len--;
            return OT_ERR_APPEND_FAILED;
        }

        // Only free the previously composed op if this is at least the 2nd
        // composition (aka 3rd op in the history). This is because the first
        // composed op for a document points to the first op in the doc's
        // history, and we don't want to free anything in the history.
        if (doc->history.len > 2) {
            ot_free_op(doc->composed);
        }
        doc->composed = new_composed;
    }

    // Don't use ot_free_op because we only want to free the ot_op struct, not
    // its components. We must also only free op if the composition was a
    // success.
    free(*op);
    *op = head;

    // The newly composed operation wil have the same hash as the appended op,
    // so we can get away with calculating the hash once and then copying it.
    hash_op(doc->composed);
    memcpy(head->hash, doc->composed->hash, 20);
    doc->size = ot_size(doc->composed);

    return OT_ERR_NONE;
}
示例#10
0
文件: server_test.c 项目: tml/libot
static void free_event() {
    if (event_op != NULL) {
        ot_free_op(event_op);
    }
}