fw4: resolve zone layer 2 devices for hw flow offloading
[project/firewall4.git] / tests / lib / mocklib / uci.uc
1 {%
2 let mocklib = global.mocklib;
3
4 let byte = (str, off) => {
5 let v = ord(str, off);
6 return length(v) ? v[0] : v;
7 };
8
9 let hash = (s) => {
10 let h = 7;
11
12 for (let i = 0; i < length(s); i++)
13 h = h * 31 + byte(s, i);
14
15 return h;
16 };
17
18 let id = (config, t, n) => {
19 while (true) {
20 let id = sprintf('cfg%08x', hash(t + n));
21
22 if (!exists(config, id))
23 return id;
24
25 n++;
26 }
27 };
28
29 let fixup_config = (config) => {
30 let rv = {};
31 let n_section = 0;
32
33 for (let stype in config) {
34 switch (type(config[stype])) {
35 case 'object':
36 config[stype] = [ config[stype] ];
37 /* fall through */
38
39 case 'array':
40 for (let idx, sobj in config[stype]) {
41 let sid, anon;
42
43 if (exists(sobj, '.name') && !exists(rv, sobj['.name'])) {
44 sid = sobj['.name'];
45 anon = false;
46 }
47 else {
48 sid = id(rv, stype, idx);
49 anon = true;
50 }
51
52 rv[sid] = {
53 '.index': n_section++,
54 ...sobj,
55 '.name': sid,
56 '.type': stype,
57 '.anonymous': anon
58 };
59 }
60
61 break;
62 }
63 }
64
65 for (let n, sid in sort(keys(rv), (a, b) => rv[a]['.index'] - rv[b]['.index']))
66 rv[sid]['.index'] = n;
67
68 return rv;
69 };
70
71 return {
72 cursor: () => ({
73 _configs: {},
74
75 load: function(file) {
76 let basename = replace(file, /^.+\//, ''),
77 path = sprintf("uci/%s.json", basename),
78 mock = mocklib.read_json_file(path);
79
80 if (!mock || mock != mock) {
81 mocklib.I("No configuration fixture defined for uci package %s.", file);
82 mocklib.I("Provide a mock configuration through the following JSON file:\n%s\n", path);
83
84 return null;
85 }
86
87 this._configs[basename] = fixup_config(mock);
88 },
89
90 _get_section: function(config, section) {
91 if (!exists(this._configs, config)) {
92 this.load(config);
93
94 if (!exists(this._configs, config))
95 return null;
96 }
97
98 let cfg = this._configs[config],
99 extended = match(section, "^@([A-Za-z0-9_-]+)\[(-?[0-9]+)\]$");
100
101 if (extended) {
102 let stype = extended[1],
103 sindex = +extended[2];
104
105 let sids = sort(
106 filter(keys(cfg), sid => cfg[sid]['.type'] == stype),
107 (a, b) => cfg[a]['.index'] - cfg[b]['.index']
108 );
109
110 if (sindex < 0)
111 sindex = sids.length + sindex;
112
113 return cfg[sids[sindex]];
114 }
115
116 return cfg[section];
117 },
118
119 get: function(config, section, option) {
120 let sobj = this._get_section(config, section);
121
122 if (option && index(option, ".") == 0)
123 return null;
124 else if (sobj && option)
125 return sobj[option];
126 else if (sobj)
127 return sobj[".type"];
128 },
129
130 get_all: function(config, section) {
131 return section ? this._get_section(config, section) : this._configs[config];
132 },
133
134 foreach: function(config, stype, cb) {
135 let rv = false;
136
137 if (exists(this._configs, config)) {
138 let cfg = this._configs[config],
139 sids = sort(keys(cfg), (a, b) => cfg[a]['.index'] - cfg[b]['.index']);
140
141 for (let i, sid in sids) {
142 if (stype == null || cfg[sid]['.type'] == stype) {
143 if (cb({ ...(cfg[sid]) }) === false)
144 break;
145
146 rv = true;
147 }
148 }
149 }
150
151 return rv;
152 }
153 })
154 };