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