about summary refs log tree commit diff stats
path: root/070table.mu
blob: f3b2c10a057a03de84ac0d36cdd85aac0f35bd50 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# A table is like an array, except that its keys are not integers but
# arbitrary types.

scenario table-read-write [
  run [
    local-scope
    tab:address:table:num:num <- new-table 30
    put-index tab, 12, 34
    1:num/raw <- index tab, 12
  ]
  memory-should-contain [
    1 <- 34
  ]
]

scenario table-read-write-non-integer [
  run [
    local-scope
    key:text <- new [abc def]
    {tab: (address table text number)} <- new-table 30
    put-index tab, key, 34
    1:num/raw <- index tab, key
  ]
  memory-should-contain [
    1 <- 34
  ]
]

container table:_key:_value [
  length:num
  capacity:num
  data:address:array:table_row:_key:_value
]

container table_row:_key:_value [
  occupied?:bool
  key:_key
  value:_value
]

def new-table capacity:num -> result:address:table:_key:_value [
  local-scope
  load-ingredients
  result <- new {(table _key _value): type}
  data:address:array:table_row:_key:_value <- new {(table_row _key _value): type}, capacity
  *result <- merge 0/length, capacity, data
]

def put-index table:address:table:_key:_value, key:_key, value:_value -> table:address:table:_key:_value [
  local-scope
  load-ingredients
  hash:num <- hash key
  hash <- abs hash
  capacity:num <- get *table, capacity:offset
  _, hash <- divide-with-remainder hash, capacity
  hash <- abs hash  # in case hash overflows into a negative integer
  table-data:address:array:table_row:_key:_value <- get *table, data:offset
  x:table_row:_key:_value <- index *table-data, hash
  occupied?:bool <- get x, occupied?:offset
  not-occupied?:bool <- not occupied?:bool
  assert not-occupied?, [can't handle collisions yet]
  new-row:table_row:_key:_value <- merge 1/true, key, value
  *table-data <- put-index *table-data, hash, new-row
]

def abs n:num -> result:num [
  local-scope
  load-ingredients
  positive?:bool <- greater-or-equal n, 0
  return-if positive?, n
  result <- multiply n, -1
]

def index table:address:table:_key:_value, key:_key -> result:_value [
  local-scope
  load-ingredients
  hash:num <- hash key
  hash <- abs hash
  capacity:num <- get *table, capacity:offset
  _, hash <- divide-with-remainder hash, capacity
  hash <- abs hash  # in case hash overflows into a negative integer
  table-data:address:array:table_row:_key:_value <- get *table, data:offset
  x:table_row:_key:_value <- index *table-data, hash
  occupied?:bool <- get x, occupied?:offset
  assert occupied?, [can't handle missing elements yet]
  result <- get x, value:offset
]
n class="w"> malloc(sizeof(DataForm)); form->type = NULL; form->title = NULL; form->instructions = NULL; form->fields = NULL; form->var_to_tag = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); form->tag_to_var = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); form->tag_ac = NULL; return form; } static FormField* _new_field(void) { FormField* field = malloc(sizeof(FormField)); field->label = NULL; field->type = NULL; field->description = NULL; field->required = FALSE; field->options = NULL; field->var = NULL; field->values = NULL; field->value_ac = NULL; return field; } void get_form_type_field_returns_null_no_fields(void** state) { DataForm* form = _new_form(); char* result = form_get_form_type_field(form); assert_null(result); form_destroy(form); } void get_form_type_field_returns_null_when_not_present(void** state) { DataForm* form = _new_form(); FormField* field = _new_field(); field->var = strdup("var1"); field->values = g_slist_append(field->values, strdup("value1")); form->fields = g_slist_append(form->fields, field); char* result = form_get_form_type_field(form); assert_null(result); form_destroy(form); } void get_form_type_field_returns_value_when_present(void** state) { DataForm* form = _new_form(); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->values = g_slist_append(field1->values, strdup("value1")); form->fields = g_slist_append(form->fields, field1); FormField* field2 = _new_field(); field2->var = strdup("FORM_TYPE"); field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); FormField* field3 = _new_field(); field3->var = strdup("var3"); field3->values = g_slist_append(field3->values, strdup("value3")); form->fields = g_slist_append(form->fields, field3); char* result = form_get_form_type_field(form); assert_string_equal(result, "value2"); form_destroy(form); } void get_field_type_returns_unknown_when_no_fields(void** state) { DataForm* form = _new_form(); form_field_type_t result = form_get_field_type(form, "tag"); assert_int_equal(result, FIELD_UNKNOWN); form_destroy(form); } void get_field_type_returns_correct_type(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_TEXT_SINGLE; field1->values = g_slist_append(field1->values, strdup("value1")); form->fields = g_slist_append(form->fields, field1); FormField* field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_TEXT_MULTI; field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); form_field_type_t result = form_get_field_type(form, "tag2"); assert_int_equal(result, FIELD_TEXT_MULTI); form_destroy(form); } void set_value_adds_when_none(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_TEXT_SINGLE; field1->values = g_slist_append(field1->values, strdup("value1")); form->fields = g_slist_append(form->fields, field1); FormField* field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_LIST_SINGLE; form->fields = g_slist_append(form->fields, field2); form_set_value(form, "tag2", "a new value"); int length = 0; char* value = NULL; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var2") == 0) { length = g_slist_length(field->values); value = field->values->data; break; } curr_field = g_slist_next(curr_field); } assert_int_equal(length, 1); assert_string_equal(value, "a new value"); form_destroy(form); } void set_value_updates_when_one(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_TEXT_SINGLE; form->fields = g_slist_append(form->fields, field1); FormField* field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_LIST_SINGLE; field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); form_set_value(form, "tag2", "a new value"); int length = 0; char* value = NULL; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var2") == 0) { length = g_slist_length(field->values); value = field->values->data; break; } curr_field = g_slist_next(curr_field); } assert_int_equal(length, 1); assert_string_equal(value, "a new value"); form_destroy(form); } void add_unique_value_adds_when_none(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_JID_MULTI; form->fields = g_slist_append(form->fields, field1); FormField* field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_LIST_SINGLE; field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); gboolean ret = form_add_unique_value(form, "tag1", "me@server.com"); int length = 0; char* value = NULL; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); value = field->values->data; break; } curr_field = g_slist_next(curr_field); } assert_true(ret); assert_int_equal(length, 1); assert_string_equal(value, "me@server.com"); form_destroy(form); } void add_unique_value_does_nothing_when_exists(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_JID_MULTI; field1->values = g_slist_append(field1->values, strdup("me@server.com")); form->fields = g_slist_append(form->fields, field1); FormField* field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_LIST_SINGLE; field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); gboolean ret = form_add_unique_value(form, "tag1", "me@server.com"); int length = 0; char* value = NULL; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); value = field->values->data; break; } curr_field = g_slist_next(curr_field); } assert_false(ret); assert_int_equal(length, 1); assert_string_equal(value, "me@server.com"); form_destroy(form); } void add_unique_value_adds_when_doesnt_exist(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_JID_MULTI; field1->values = g_slist_append(field1->values, strdup("dolan@server.com")); field1->values = g_slist_append(field1->values, strdup("kieran@server.com")); field1->values = g_slist_append(field1->values, strdup("chi@server.com")); form->fields = g_slist_append(form->fields, field1); FormField* field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_LIST_SINGLE; field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); gboolean ret = form_add_unique_value(form, "tag1", "me@server.com"); int length = 0; int count = 0; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); GSList* curr_value = field->values; while (curr_value != NULL) { if (g_strcmp0(curr_value->data, "me@server.com") == 0) { count++; } curr_value = g_slist_next(curr_value); } break; } curr_field = g_slist_next(curr_field); } assert_true(ret); assert_int_equal(length, 4); assert_int_equal(count, 1); form_destroy(form); } void add_value_adds_when_none(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; form->fields = g_slist_append(form->fields, field1); form_add_value(form, "tag1", "somevalue"); int length = 0; char* value = NULL; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); value = field->values->data; break; } curr_field = g_slist_next(curr_field); } assert_int_equal(length, 1); assert_string_equal(value, "somevalue"); form_destroy(form); } void add_value_adds_when_some(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("some text")); field1->values = g_slist_append(field1->values, strdup("some more text")); field1->values = g_slist_append(field1->values, strdup("yet some more text")); form->fields = g_slist_append(form->fields, field1); form_add_value(form, "tag1", "new value"); int num_values = 0; int new_value_count = 0; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { GSList* curr_value = field->values; while (curr_value != NULL) { num_values++; if (g_strcmp0(curr_value->data, "new value") == 0) { new_value_count++; } curr_value = g_slist_next(curr_value); } break; } curr_field = g_slist_next(curr_field); } assert_int_equal(num_values, 4); assert_int_equal(new_value_count, 1); form_destroy(form); } void add_value_adds_when_exists(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("some text")); field1->values = g_slist_append(field1->values, strdup("some more text")); field1->values = g_slist_append(field1->values, strdup("yet some more text")); field1->values = g_slist_append(field1->values, strdup("new value")); form->fields = g_slist_append(form->fields, field1); form_add_value(form, "tag1", "new value"); int num_values = 0; int new_value_count = 0; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { GSList* curr_value = field->values; while (curr_value != NULL) { num_values++; if (g_strcmp0(curr_value->data, "new value") == 0) { new_value_count++; } curr_value = g_slist_next(curr_value); } break; } curr_field = g_slist_next(curr_field); } assert_int_equal(num_values, 5); assert_int_equal(new_value_count, 2); form_destroy(form); } void remove_value_does_nothing_when_none(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_value(form, "tag1", "some value"); int length = -1; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); } curr_field = g_slist_next(curr_field); } assert_false(res); assert_int_equal(length, 0); form_destroy(form); } void remove_value_does_nothing_when_doesnt_exist(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value1")); field1->values = g_slist_append(field1->values, strdup("value2")); field1->values = g_slist_append(field1->values, strdup("value3")); field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_value(form, "tag1", "value5"); int length = -1; int value_count = 0; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); GSList* curr_value = field->values; while (curr_value != NULL) { if (g_strcmp0(curr_value->data, "value5") == 0) { value_count++; } curr_value = g_slist_next(curr_value); } } curr_field = g_slist_next(curr_field); } assert_false(res); assert_int_equal(length, 4); assert_int_equal(value_count, 0); form_destroy(form); } void remove_value_removes_when_one(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_value(form, "tag1", "value4"); int length = -1; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); } curr_field = g_slist_next(curr_field); } assert_true(res); assert_int_equal(length, 0); form_destroy(form); } void remove_value_removes_when_many(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value1")); field1->values = g_slist_append(field1->values, strdup("value2")); field1->values = g_slist_append(field1->values, strdup("value3")); field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_value(form, "tag1", "value2"); int length = -1; int value_count = 0; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); GSList* curr_value = field->values; while (curr_value != NULL) { if (g_strcmp0(curr_value->data, "value2") == 0) { value_count++; } curr_value = g_slist_next(curr_value); } } curr_field = g_slist_next(curr_field); } assert_true(res); assert_int_equal(length, 3); assert_int_equal(value_count, 0); form_destroy(form); } void remove_text_multi_value_does_nothing_when_none(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_text_multi_value(form, "tag1", 3); int length = -1; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); } curr_field = g_slist_next(curr_field); } assert_false(res); assert_int_equal(length, 0); form_destroy(form); } void remove_text_multi_value_does_nothing_when_doesnt_exist(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value1")); field1->values = g_slist_append(field1->values, strdup("value2")); field1->values = g_slist_append(field1->values, strdup("value3")); field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_text_multi_value(form, "tag1", 5); int length = -1; int value_count = 0; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); GSList* curr_value = field->values; while (curr_value != NULL) { if (g_strcmp0(curr_value->data, "value5") == 0) { value_count++; } curr_value = g_slist_next(curr_value); } } curr_field = g_slist_next(curr_field); } assert_false(res); assert_int_equal(length, 4); assert_int_equal(value_count, 0); form_destroy(form); } void remove_text_multi_value_removes_when_one(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_text_multi_value(form, "tag1", 1); int length = -1; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); } curr_field = g_slist_next(curr_field); } assert_true(res); assert_int_equal(length, 0); form_destroy(form); } void remove_text_multi_value_removes_when_many(void** state) { DataForm* form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField* field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value1")); field1->values = g_slist_append(field1->values, strdup("value2")); field1->values = g_slist_append(field1->values, strdup("value3")); field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_text_multi_value(form, "tag1", 2); int length = -1; int value_count = 0; GSList* curr_field = form->fields; while (curr_field != NULL) { FormField* field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); GSList* curr_value = field->values; while (curr_value != NULL) { if (g_strcmp0(curr_value->data, "value2") == 0) { value_count++; } curr_value = g_slist_next(curr_value); } } curr_field = g_slist_next(curr_field); } assert_true(res); assert_int_equal(length, 3); assert_int_equal(value_count, 0); form_destroy(form); }