==> tests/mode.c <==1/* place.rs: modes_and_assignments, roles_input_authority, auto_weights_the_slow_machine_down. */
2#include "mesh/check.h"
3#include "mesh/place_mode.h"
4#include "mesh/mt.h"
5
6#include <stdlib.h>
7
8static bool target(const char *w, uint32_t n, mpm_target *t) {
9 mt_strs ws = mt_words(w);
10 char *err = NULL;
11 bool ok = mpm_parse(ws.v, ws.n, n, 4, t, &err);
12 free(err);
13 mt_strs_free(&ws);
14 return ok;
15}
16
17static mpm_mode split(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { return mpm_split(mpm_assign_new((uint32_t[]){a, b, c, d}, 4)); }
18
19static void check_split(const char *w, uint32_t n, mpm_mode want) {
20 mpm_target t;
21 CHECK(target(w, n, &t) && !t.is_auto && mpm_mode_eq(&t.mode, &want));
22}
23
24static void check_list(const uint32_t *sys, const uint32_t *ns, size_t n, const char *want) {
25 mpm_assign a = mpm_auto(sys, ns, n, 4);
26 char *l = mpm_list(&a);
27 CHECK_S(l, want);
28 free(l);
29}
30
31int main(void) {
32 mpm_target t;
33 CHECK(target("pin 2", 3, &t) && t.mode.kind == MPM_PIN && t.mode.pin == 2);
34 CHECK(!target("pin 3", 3, &t) && !target("pin", 3, &t) && !target("both", 3, &t));
35 check_split("split", 2, split(0, 0, 1, 1));
36 check_split("split", 3, split(0, 0, 1, 2));
37 check_split("split", 4, split(0, 1, 2, 3));
38 check_split("split", 8, split(0, 1, 2, 3));
39 check_split("split 2,1", 3, split(2, 2, 1, 1));
40 check_split("split 0,2,1", 4, split(0, 0, 2, 1));
41 check_split("split 1:3,2:1", 3, split(1, 1, 1, 2));
42 check_split("split 0,0,1,2", 3, split(0, 0, 1, 2));
43 check_split("split 2,0,2,2", 3, split(2, 0, 2, 2));
44 CHECK(target("split auto", 3, &t) && t.is_auto && t.auto_mask == 7);
45 const char *bad[] = {"split 0,0", "split 0,1,2,3,0", "split 1:2,2:1", "split 1:2,1:2", "split 0:0,1:4", "split 0,3", "split x"};
46 for (int i = 0; i < 7; i++) CHECK(!target(bad[i], 3, &t));
47 char *err = NULL;
48 mt_strs w = mt_words("split 1:2,1:2");
49 CHECK(!mpm_parse(w.v, w.n, 3, 4, &t, &err));
50 CHECK_S(err, "split 1:2,1:2: a system twice");
51 free(err);
52 mt_strs_free(&w);
53 w = mt_words("pin 7");
54 CHECK(!mpm_parse(w.v, w.n, 3, 4, &t, &err));
55 CHECK_S(err, "\"7\": not a system of this cluster (0..2)");
56 free(err);
57 mt_strs_free(&w);
58 w = mt_words("frob");
59 CHECK(!mpm_parse(w.v, w.n, 3, 4, &t, &err));
60 CHECK_S(err, "usage: place <name> [local | pin 0..2 | split [auto | a,b,.. | a:parts,b:parts,..]], not \"frob\"");
61 free(err);
62 mt_strs_free(&w);
63 mpm_assign a = mpm_assign_new((uint32_t[]){0, 0, 1, 2}, 4);
64 char *l = mpm_list(&a);
65 CHECK(mpm_owner(&a) == 0 && mpm_mask_of(&a, 0) == 3 && mpm_mask_of(&a, 1) == 4 && mpm_mask_of(&a, 2) == 8 && mpm_mask_of(&a, 3) == 0 && mpm_members(&a) == 7);
66 CHECK_S(l, "0,0,1,2");
67 free(l);
68 /* Wire codes: every mode round-trips; bad ones are refused. */
69 mpm_mode modes[] = {mpm_local(), mpm_pin(0), mpm_pin(7), split(0, 0, 1, 2), split(3, 1, 1, 1)};
70 for (int i = 0; i < 5; i++) {
71 uint32_t c, s;
72 uint8_t ab[MESH_PLACE_PARTS_MAX];
73 mpm_code(&modes[i], &c, &s);
74 mpm_assign_bytes(&modes[i], ab);
75 mpm_mode back;
76 CHECK(mpm_from_code(c, s, ab, MESH_PLACE_PARTS_MAX, &back, &err) && mpm_mode_eq(&back, &modes[i]));
77 }
78 mpm_mode s4 = split(0, 1, 2, 3);
79 uint8_t gap[MESH_PLACE_PARTS_MAX];
80 mpm_assign_bytes(&s4, gap);
81 gap[1] = MESH_PART_NONE;
82 mpm_mode m;
83 CHECK(!mpm_from_code(MESH_PLACE_SPLIT, 0, gap, MESH_PLACE_PARTS_MAX, &m, &err));
84 CHECK_S(err, "split: a gap in the assignment");
85 free(err);
86 mpm_mode s2 = mpm_split(mpm_assign_new((uint32_t[]){0, 1}, 2));
87 uint8_t b2[MESH_PLACE_PARTS_MAX];
88 mpm_assign_bytes(&s2, b2);
89 CHECK(!mpm_from_code(MESH_PLACE_SPLIT, 1, b2, MESH_PLACE_PARTS_MAX, &m, &err));
90 free(err);
91 CHECK(!mpm_from_code(MESH_PLACE_PIN, 8, NULL, 0, &m, &err));
92 free(err);
93 CHECK(!mpm_from_code(7, 0, NULL, 0, &m, &err));
94 CHECK_S(err, "bad placement 7/0");
95 free(err);
96 mpm_mode s09 = mpm_split(mpm_assign_new((uint32_t[]){0, 9}, 2)), s01 = mpm_split(mpm_assign_new((uint32_t[]){0, 1}, 2)), p3 = mpm_pin(3);
97 CHECK(!mpm_fits(&s09, 3, 2, &err));
98 free(err);
99 CHECK(!mpm_fits(&s01, 3, 4, &err));
100 free(err);
101 CHECK(!mpm_fits(&p3, 3, 4, &err));
102 free(err);
103 mpm_mode lab = split(0, 0, 1, 2);
104 l = mpm_label(&lab);
105 CHECK_S(l, "split 0,0,1,2");
106 free(l);
107 mpm_mode p0 = mpm_pin(0), loc = mpm_local();
108 CHECK(!mpm_allowed(&s01, MESH_PLACE_CAP_PIN, &err));
109 free(err);
110 CHECK(mpm_allowed(&p0, MESH_PLACE_CAP_PIN, &err));
111 CHECK(!mpm_allowed(&loc, MESH_PLACE_CAP_NONE, &err));
112 free(err);
113
114 /* roles_input_authority */
115 mpm_mode s = split(1, 1, 0, 2);
116 CHECK(mpm_role_of(&s, 0) == MPM_ROLE_FOLLOWER && mpm_role_of(&s, 1) == MPM_ROLE_OWNER && mpm_role_of(&s, 2) == MPM_ROLE_FOLLOWER &&
117 mpm_role_of(&s, 3) == MPM_ROLE_MIRROR);
118 mpm_mode pin2 = mpm_pin(2);
119 CHECK(mpm_role_of(&pin2, 2) == MPM_ROLE_RUNNER && mpm_role_of(&pin2, 0) == MPM_ROLE_MIRROR && mpm_role_of(&loc, 1) == MPM_ROLE_LOCAL);
120 CHECK(!mpm_runs(MPM_ROLE_MIRROR) && mpm_runs(MPM_ROLE_FOLLOWER));
121 CHECK(mpm_input_to(&loc, 3) == 3 && mpm_input_to(&pin2, 0) == 2 && mpm_input_to(&s, 3) == 1);
122 CHECK(mpm_parts_of(&s, 1, 4) == 3 && mpm_parts_of(&s, 3, 4) == 0 && mpm_parts_of(&pin2, 2, 4) == 15 && mpm_parts_of(&pin2, 0, 4) == 0);
123 CHECK(mpm_authority(&p0, &pin2) == 0 && mpm_authority(&loc, &s) == 1 && mpm_authority(&s, &loc) == 1 && mpm_authority(&loc, &pin2) == 2);
124
125 /* auto_weights_the_slow_machine_down */
126 check_list((uint32_t[]){0, 1, 2, 3}, (uint32_t[]){100, 100, 100, 100}, 4, "0,1,2,3");
127 check_list((uint32_t[]){0, 1}, (uint32_t[]){100, 100}, 2, "0,0,1,1");
128 check_list((uint32_t[]){0, 1, 2}, (uint32_t[]){100, 100, 150}, 3, "0,0,1,2");
129 check_list((uint32_t[]){0, 1, 2}, (uint32_t[]){150, 100, 100}, 3, "1,1,0,2");
130 check_list((uint32_t[]){0, 1, 2}, (uint32_t[]){100, 100, 300}, 3, "0,0,1,1");
131 check_list((uint32_t[]){0, 1, 2}, (uint32_t[]){300, 100, 100}, 3, "1,1,2,2");
132 check_list((uint32_t[]){0, 1}, (uint32_t[]){100, 1000}, 2, "0,0,0,0");
133 check_list((uint32_t[]){0, 1, 2}, (uint32_t[]){0, 0, 0}, 3, "0,0,1,2");
134 return mesh_check_done();
135}