manyfest 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.config/code-server/config.yaml +4 -0
- package/.config/configstore/update-notifier-npm-check-updates.json +4 -0
- package/.config/configstore/update-notifier-npm.json +4 -0
- package/.config/installation/UI-Requirements.md +32 -0
- package/.config/installation/install_luxury_code.js +105 -0
- package/.config/installation/install_luxury_default_configuration.json +45 -0
- package/.config/installation/install_luxury_interaction.json +3 -0
- package/.config/installation/precedent.1.0.5.js +339 -0
- package/.config/luxury-extras/.vscode/launch.json +46 -0
- package/.config/luxury-extras/Dockerfile_LUXURYCode +39 -0
- package/.config/luxury-extras/MySQL/Dockerfile_LUXURYCODE_MySQL +65 -0
- package/.config/luxury-extras/MySQL/MySQL-Laden-Entry.sh +17 -0
- package/.config/luxury-extras/MySQL/MySQL-Security.sql +5 -0
- package/.vscode/launch.json +46 -0
- package/Dockerfile_LUXURYCode +39 -0
- package/LICENSE +21 -0
- package/README.md +234 -0
- package/debug/Harness.js +20 -0
- package/diagrams/Mascot.jpg +0 -0
- package/gulpfile.js +62 -0
- package/package.json +67 -0
- package/source/Manyfest-Browser-Shim.js +15 -0
- package/source/Manyfest-LogToConsole.js +19 -0
- package/source/Manyfest.js +357 -0
- package/test/Manyfest_tests.js +167 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license MIT
|
|
3
|
+
* @author <steven@velozo.com>
|
|
4
|
+
*/
|
|
5
|
+
let libSimpleLog = require('./Manyfest-LogToConsole.js');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Manyfest object address-based descriptions and manipulations.
|
|
9
|
+
*
|
|
10
|
+
* @class Manyfest
|
|
11
|
+
*/
|
|
12
|
+
class Manyfest
|
|
13
|
+
{
|
|
14
|
+
constructor(pManifest, pInfoLog, pErrorLog)
|
|
15
|
+
{
|
|
16
|
+
// Wire in logging
|
|
17
|
+
this.logInfo = (typeof(pInfoLog) === 'function') ? pInfoLog : libSimpleLog;
|
|
18
|
+
this.logError = (typeof(pErrorLog) === 'function') ? pErrorLog : libSimpleLog;
|
|
19
|
+
|
|
20
|
+
this.options = (
|
|
21
|
+
{
|
|
22
|
+
strict: false
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
this.scope = undefined;
|
|
26
|
+
this.elementAddresses = undefined;
|
|
27
|
+
this.elementHashes = undefined;
|
|
28
|
+
this.elementDescriptors = undefined;
|
|
29
|
+
|
|
30
|
+
this.reset();
|
|
31
|
+
|
|
32
|
+
if (typeof(pManifest) === 'object')
|
|
33
|
+
{
|
|
34
|
+
this.loadManifest(pManifest);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/*************************************************************************
|
|
39
|
+
* Schema Manifest Loading, Reading, Manipulation and Serialization Functions
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
// Reset critical manifest properties
|
|
43
|
+
reset()
|
|
44
|
+
{
|
|
45
|
+
this.scope = 'DEFAULT';
|
|
46
|
+
this.elementAddresses = [];
|
|
47
|
+
this.elementHashes = {};
|
|
48
|
+
this.elementDescriptors = {};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Deserialize a Manifest from a string
|
|
52
|
+
deserialize(pManifestString)
|
|
53
|
+
{
|
|
54
|
+
// TODO: Add guards for bad manifest string
|
|
55
|
+
return this.loadManifest(JSON.parse(pManifestString));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Load a manifest from an object
|
|
59
|
+
loadManifest(pManifest)
|
|
60
|
+
{
|
|
61
|
+
if (typeof(pManifest) !== 'object')
|
|
62
|
+
{
|
|
63
|
+
this.logError(`(${this.scope}) Error loading manifest; expecting an object but parameter was type ${typeof(pManifest)}.`);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (pManifest.hasOwnProperty('Scope'))
|
|
68
|
+
{
|
|
69
|
+
if (typeof(pManifest.Scope) === 'string')
|
|
70
|
+
{
|
|
71
|
+
this.scope = pManifest.Scope;
|
|
72
|
+
}
|
|
73
|
+
else
|
|
74
|
+
{
|
|
75
|
+
this.logError(`(${this.scope}) Error loading scope from manifest; expecting a string but property was type ${typeof(pManifest.Scope)}.`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else
|
|
79
|
+
{
|
|
80
|
+
this.logError(`(${this.scope}) Error loading scope from manifest object. Property "Scope" does not exist in the root of the object.`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (pManifest.hasOwnProperty('Descriptors'))
|
|
84
|
+
{
|
|
85
|
+
if (typeof(pManifest.Descriptors) === 'object')
|
|
86
|
+
{
|
|
87
|
+
let tmpDescriptionAddresses = Object.keys(pManifest.Descriptors);
|
|
88
|
+
for (let i = 0; i < tmpDescriptionAddresses.length; i++)
|
|
89
|
+
{
|
|
90
|
+
this.addDescriptor(tmpDescriptionAddresses[i], pManifest.Descriptors[tmpDescriptionAddresses[i]]);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else
|
|
94
|
+
{
|
|
95
|
+
this.logError(`(${this.scope}) Error loading description object from manifest object. Expecting an object in 'Manifest.Descriptors' but the property was type ${typeof(pManifest.Description)}.`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else
|
|
99
|
+
{
|
|
100
|
+
this.logError(`(${this.scope}) Error loading object description from manifest object. Property "Descriptors" does not exist in the root of the object.`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Serialize the Manifest to a string
|
|
105
|
+
serialize()
|
|
106
|
+
{
|
|
107
|
+
return JSON.stringify(this.getManifest());
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
getManifest()
|
|
111
|
+
{
|
|
112
|
+
let tmpManifest = (
|
|
113
|
+
{
|
|
114
|
+
Scope: this.scope,
|
|
115
|
+
Descriptors: JSON.parse(JSON.stringify(this.elementDescriptors))
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Add a descriptor to the manifest
|
|
120
|
+
addDescriptor(pAddress, pDescriptor)
|
|
121
|
+
{
|
|
122
|
+
if (typeof(pDescriptor) === 'object')
|
|
123
|
+
{
|
|
124
|
+
// Add the Address into the Descriptor if it doesn't exist:
|
|
125
|
+
if (!pDescriptor.hasOwnProperty('Address'))
|
|
126
|
+
{
|
|
127
|
+
pDescriptor.Address = pAddress;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!this.elementDescriptors.hasOwnProperty(pAddress))
|
|
131
|
+
{
|
|
132
|
+
this.elementAddresses.push(pAddress);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Add the element descriptor to the schema
|
|
136
|
+
this.elementDescriptors[pAddress] = pDescriptor;
|
|
137
|
+
|
|
138
|
+
// Always add the address as a hash
|
|
139
|
+
// TODO: Check if this is a good idea or not.
|
|
140
|
+
// Collisions are bound to happen with both representations of the address/hash in here.
|
|
141
|
+
this.elementHashes[pAddress] = pAddress;
|
|
142
|
+
|
|
143
|
+
if (pDescriptor.hasOwnProperty('Hash'))
|
|
144
|
+
{
|
|
145
|
+
this.elementHashes[pDescriptor.Hash] = pAddress;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
else
|
|
151
|
+
{
|
|
152
|
+
this.logError(`(${this.scope}) Error loading object descriptor for address '${pAddress}' from manifest object. Expecting an object but property was type ${typeof(pDescriptor)}.`);
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
getDescriptorByHash(pHash)
|
|
158
|
+
{
|
|
159
|
+
if (this.elementHashes.hasOwnProperty(pHash))
|
|
160
|
+
{
|
|
161
|
+
return this.getDescriptor(this.elementHashes[pHash]);
|
|
162
|
+
}
|
|
163
|
+
else
|
|
164
|
+
{
|
|
165
|
+
this.logError(`(${this.scope}) Error in getDescriptorByHash; the Hash ${pHash} doesn't exist in the schema.`);
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
getDescriptor(pAddress)
|
|
171
|
+
{
|
|
172
|
+
return this.elementDescriptors[pAddress];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/*************************************************************************
|
|
176
|
+
* Beginning of Object Manipulation (read & write) Functions
|
|
177
|
+
*/
|
|
178
|
+
// Get the value of an element by its hash
|
|
179
|
+
getValueByHash (pObject, pHash)
|
|
180
|
+
{
|
|
181
|
+
if (this.elementHashes.hasOwnProperty(pHash))
|
|
182
|
+
{
|
|
183
|
+
return this.getValueAtAddress(pObject, this.elementHashes[pHash]);
|
|
184
|
+
}
|
|
185
|
+
else
|
|
186
|
+
{
|
|
187
|
+
this.logError(`(${this.scope}) Error in getValueByHash; the Hash ${pHash} doesn't exist in the schema.`);
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Get the value of an element at an address
|
|
193
|
+
getValueAtAddress (pObject, pAddress)
|
|
194
|
+
{
|
|
195
|
+
// Make sure pObject is an object
|
|
196
|
+
if (!typeof(pObject) === 'object') return undefined;
|
|
197
|
+
// Make sure pAddress is a string
|
|
198
|
+
if (!typeof(pAddress) === 'string') return undefined;
|
|
199
|
+
|
|
200
|
+
let tmpSeparatorIndex = pAddress.indexOf('.');
|
|
201
|
+
|
|
202
|
+
if (tmpSeparatorIndex === -1)
|
|
203
|
+
{
|
|
204
|
+
// Now is the point in recursion to return the value in the address
|
|
205
|
+
return pObject[pAddress];
|
|
206
|
+
}
|
|
207
|
+
else
|
|
208
|
+
{
|
|
209
|
+
let tmpSubObjectName = pAddress.substring(0, tmpSeparatorIndex);
|
|
210
|
+
let tmpNewAddress = pAddress.substring(tmpSeparatorIndex+1);
|
|
211
|
+
|
|
212
|
+
// If there is an object property already named for the sub object, but it isn't an object
|
|
213
|
+
// then the system can't set the value in there. Error and abort!
|
|
214
|
+
if (pObject.hasOwnProperty(tmpSubObjectName) && typeof(pObject[tmpSubObjectName]) !== 'object')
|
|
215
|
+
{
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
else if (pObject.hasOwnProperty(tmpSubObjectName))
|
|
219
|
+
{
|
|
220
|
+
// If there is already a subobject pass that to the recursive thingy
|
|
221
|
+
return this.getValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress);
|
|
222
|
+
}
|
|
223
|
+
else
|
|
224
|
+
{
|
|
225
|
+
// Create a subobject and then pass that
|
|
226
|
+
pObject[tmpSubObjectName] = {};
|
|
227
|
+
return this.getValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Set the value of an element by its hash
|
|
233
|
+
setValueByHash(pObject, pHash, pValue)
|
|
234
|
+
{
|
|
235
|
+
if (this.elementHashes.hasOwnProperty(pHash))
|
|
236
|
+
{
|
|
237
|
+
return this.setValueAtAddress(pObject, this.elementHashes[pHash], pValue);
|
|
238
|
+
}
|
|
239
|
+
else
|
|
240
|
+
{
|
|
241
|
+
this.logError(`(${this.scope}) Error in setValueByHash; the Hash ${pHash} doesn't exist in the schema. Value ${pValue} will not be written!`);
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Set the value of an element at an address
|
|
247
|
+
setValueAtAddress (pObject, pAddress, pValue)
|
|
248
|
+
{
|
|
249
|
+
// Make sure pObject is an object
|
|
250
|
+
if (!typeof(pObject) === 'object') return false;
|
|
251
|
+
// Make sure pAddress is a string
|
|
252
|
+
if (!typeof(pAddress) === 'string') return false;
|
|
253
|
+
|
|
254
|
+
let tmpSeparatorIndex = pAddress.indexOf('.');
|
|
255
|
+
|
|
256
|
+
if (tmpSeparatorIndex === -1)
|
|
257
|
+
{
|
|
258
|
+
// Now is the time to set the value in the object
|
|
259
|
+
pObject[pAddress] = pValue;
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
else
|
|
263
|
+
{
|
|
264
|
+
let tmpSubObjectName = pAddress.substring(0, tmpSeparatorIndex);
|
|
265
|
+
let tmpNewAddress = pAddress.substring(tmpSeparatorIndex+1);
|
|
266
|
+
|
|
267
|
+
// If there is an object property already named for the sub object, but it isn't an object
|
|
268
|
+
// then the system can't set the value in there. Error and abort!
|
|
269
|
+
if (pObject.hasOwnProperty(tmpSubObjectName) && typeof(pObject[tmpSubObjectName]) !== 'object')
|
|
270
|
+
{
|
|
271
|
+
if (!pObject.hasOwnProperty('__ERROR'))
|
|
272
|
+
pObject['__ERROR'] = {};
|
|
273
|
+
// Put it in an error object so data isn't lost
|
|
274
|
+
pObject['__ERROR'][pAddress] = pValue;
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
else if (pObject.hasOwnProperty(tmpSubObjectName))
|
|
278
|
+
{
|
|
279
|
+
// If there is already a subobject pass that to the recursive thingy
|
|
280
|
+
return this.setValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress, pValue);
|
|
281
|
+
}
|
|
282
|
+
else
|
|
283
|
+
{
|
|
284
|
+
// Create a subobject and then pass that
|
|
285
|
+
pObject[tmpSubObjectName] = {};
|
|
286
|
+
return this.setValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress, pValue);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
setValueAtAddressInContainer(pRecordObject, pFormContainerAddress, pFormContainerIndex, pFormValueAddress, pFormValue)
|
|
292
|
+
{
|
|
293
|
+
// First see if there *is* a container object
|
|
294
|
+
let tmpContainerObject = this.getValueAtAddress(pRecordObject, pFormContainerAddress);
|
|
295
|
+
|
|
296
|
+
if (typeof(pFormContainerAddress) !== 'string') return false;
|
|
297
|
+
|
|
298
|
+
let tmpFormContainerIndex = parseInt(pFormContainerIndex, 10);
|
|
299
|
+
if (isNaN(tmpFormContainerIndex)) return false;
|
|
300
|
+
|
|
301
|
+
if ((typeof(tmpContainerObject) !== 'object') || (!Array.isArray(tmpContainerObject)))
|
|
302
|
+
{
|
|
303
|
+
// Check if there is a value here and we want to store it in the "__OverwrittenData" thing
|
|
304
|
+
tmpContainerObject = [];
|
|
305
|
+
this.setValueAtAddress(pRecordObject, pFormContainerAddress, tmpContainerObject);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
for (let i = 0; (tmpContainerObject.length + i) <= (tmpFormContainerIndex+1); i++)
|
|
309
|
+
{
|
|
310
|
+
// Add objects to this container until it has enough
|
|
311
|
+
tmpContainerObject.push({});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Now set the value *in* the container object
|
|
315
|
+
return this.setValueAtAddress(tmpContainerObject[tmpFormContainerIndex], pFormValueAddress, pFormValue);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
// Validate the consistency of an object against the schema
|
|
320
|
+
validate(pObject)
|
|
321
|
+
{
|
|
322
|
+
let tmpValidationData =
|
|
323
|
+
{
|
|
324
|
+
Error: null,
|
|
325
|
+
Errors: [],
|
|
326
|
+
MissingElements:[]
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
if (typeof(pObject) !== 'object')
|
|
330
|
+
{
|
|
331
|
+
tmpValidationData.Error = true;
|
|
332
|
+
tmpValidationData.Errors.push(`Expected passed in object to be type object but was passed in ${typeof(pObject)}`);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Now enumerate through the values and check for anomalies
|
|
336
|
+
for (let i = 0; i < this.elementAddresses.length; i++)
|
|
337
|
+
{
|
|
338
|
+
let tmpDescriptor = this.getDescriptor(this.elementAddresses[i]);
|
|
339
|
+
let tmpValue = this.getValueAtAddress(pObject, tmpDescriptor.Address);
|
|
340
|
+
|
|
341
|
+
if (typeof(tmpValue) == 'undefined')
|
|
342
|
+
{
|
|
343
|
+
tmpValidationData.MissingElements.push(tmpDescriptor.Address);
|
|
344
|
+
|
|
345
|
+
if (tmpDescriptor.Required || this.options.strict)
|
|
346
|
+
{
|
|
347
|
+
tmpValidationData.Error = true;
|
|
348
|
+
tmpValidationData.Errors.push(`Element at address '${tmpDescriptor.Address}' is flagged Required but is not present.`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return tmpValidationData;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
module.exports = Manyfest;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for Meadow
|
|
3
|
+
*
|
|
4
|
+
* @license MIT
|
|
5
|
+
*
|
|
6
|
+
* @author Steven Velozo <steven@velozo.com>
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
var Chai = require("chai");
|
|
10
|
+
var Expect = Chai.expect;
|
|
11
|
+
|
|
12
|
+
let libManyfest = require('../source/Manyfest.js');
|
|
13
|
+
|
|
14
|
+
suite
|
|
15
|
+
(
|
|
16
|
+
'Manyfest Basic',
|
|
17
|
+
function()
|
|
18
|
+
{
|
|
19
|
+
setup
|
|
20
|
+
(
|
|
21
|
+
()=>
|
|
22
|
+
{
|
|
23
|
+
// No custom per-test spool-up required
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
suite
|
|
28
|
+
(
|
|
29
|
+
'Object Sanity',
|
|
30
|
+
()=>
|
|
31
|
+
{
|
|
32
|
+
test
|
|
33
|
+
(
|
|
34
|
+
'The class should initialize itself into a happy little object.',
|
|
35
|
+
(fTestComplete)=>
|
|
36
|
+
{
|
|
37
|
+
let _Manyfest = new libManyfest({});
|
|
38
|
+
Expect(_Manyfest)
|
|
39
|
+
.to.be.an('object', 'Manyfest should initialize as an object with no parameters.');
|
|
40
|
+
fTestComplete();
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
test
|
|
44
|
+
(
|
|
45
|
+
'Default properties should be automatically set.',
|
|
46
|
+
(fTestComplete)=>
|
|
47
|
+
{
|
|
48
|
+
let _Manyfest = new libManyfest({});
|
|
49
|
+
Expect(_Manyfest.scope)
|
|
50
|
+
.to.be.a('string', 'Manyfest should have a scope.');
|
|
51
|
+
Expect(_Manyfest.scope)
|
|
52
|
+
.to.equal('DEFAULT', 'Manyfest should default to the Scope DEFAULT.');
|
|
53
|
+
fTestComplete();
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
suite
|
|
60
|
+
(
|
|
61
|
+
'Object Access',
|
|
62
|
+
()=>
|
|
63
|
+
{
|
|
64
|
+
test
|
|
65
|
+
(
|
|
66
|
+
'Properties should be gettable and settable without a schema.',
|
|
67
|
+
(fTestComplete)=>
|
|
68
|
+
{
|
|
69
|
+
let _Manyfest = new libManyfest({});
|
|
70
|
+
let _SimpleObject = {Name:'Bob',Age:31,Pets:{Fido:'Dog',Spot:'Cat'}};
|
|
71
|
+
|
|
72
|
+
Expect(_Manyfest.getValueAtAddress(_SimpleObject,'Name'))
|
|
73
|
+
.to.equal('Bob');
|
|
74
|
+
|
|
75
|
+
_Manyfest.setValueAtAddress(_SimpleObject,'Name','Jim');
|
|
76
|
+
|
|
77
|
+
Expect(_Manyfest.getValueAtAddress(_SimpleObject,'Name'))
|
|
78
|
+
.to.equal('Jim');
|
|
79
|
+
|
|
80
|
+
fTestComplete();
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
test
|
|
84
|
+
(
|
|
85
|
+
'Properties should be accessible via Hash.',
|
|
86
|
+
(fTestComplete)=>
|
|
87
|
+
{
|
|
88
|
+
let animalManyfest = new libManyfest(
|
|
89
|
+
{
|
|
90
|
+
"Scope": "Animal",
|
|
91
|
+
"Descriptors":
|
|
92
|
+
{
|
|
93
|
+
"IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" },
|
|
94
|
+
"Name": { "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." },
|
|
95
|
+
"Type": { "Description":"Whether or not the animal is wild, domesticated, agricultural, in a research lab or a part of a zoo.." },
|
|
96
|
+
"MedicalStats":
|
|
97
|
+
{
|
|
98
|
+
"Name":"Medical Statistics", "Description":"Basic medical statistics for this animal"
|
|
99
|
+
},
|
|
100
|
+
"MedicalStats.Temps.MinET": { "Name":"Minimum Environmental Temperature", "NameShort":"MinET", "Description":"Safest minimum temperature for this animal to survive in."},
|
|
101
|
+
"MedicalStats.Temps.MaxET": { "Name":"Maximum Environmental Temperature", "NameShort":"MaxET", "Description":"Safest maximum temperature for this animal to survive in."},
|
|
102
|
+
"MedicalStats.Temps.CET":
|
|
103
|
+
{
|
|
104
|
+
"Name":"Comfortable Environmental Temperature",
|
|
105
|
+
"NameShort":"Comf Env Temp",
|
|
106
|
+
"Hash":"ComfET",
|
|
107
|
+
"Description":"The most comfortable temperature for this animal to survive in."
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
Expect(animalManyfest.getValueByHash({MedicalStats: { Temps: { CET:200 }},Name:'Froggy'}, 'ComfET'))
|
|
113
|
+
.to.equal(200);
|
|
114
|
+
|
|
115
|
+
fTestComplete();
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
test
|
|
119
|
+
(
|
|
120
|
+
'Validate should check that required elements exist',
|
|
121
|
+
(fTestComplete)=>
|
|
122
|
+
{
|
|
123
|
+
let animalManyfest = new libManyfest(
|
|
124
|
+
{
|
|
125
|
+
"Scope": "Animal",
|
|
126
|
+
"Descriptors":
|
|
127
|
+
{
|
|
128
|
+
"IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" },
|
|
129
|
+
"Name": { "Required":true, "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." }
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
let tmpValidationResults = animalManyfest.validate({MedicalStats: { Temps: { CET:200 }},Name:'Froggy'});
|
|
134
|
+
|
|
135
|
+
Expect(tmpValidationResults.Error)
|
|
136
|
+
.to.equal(null);
|
|
137
|
+
|
|
138
|
+
fTestComplete();
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
test
|
|
142
|
+
(
|
|
143
|
+
'Validate should error when required elements do not exist',
|
|
144
|
+
(fTestComplete)=>
|
|
145
|
+
{
|
|
146
|
+
let animalManyfest = new libManyfest(
|
|
147
|
+
{
|
|
148
|
+
"Scope": "Animal",
|
|
149
|
+
"Descriptors":
|
|
150
|
+
{
|
|
151
|
+
"IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" },
|
|
152
|
+
"Name": { "Required":true, "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." }
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
let tmpValidationResults = animalManyfest.validate({MedicalStats: { Temps: { CET:200 }}});
|
|
157
|
+
|
|
158
|
+
Expect(tmpValidationResults.Error)
|
|
159
|
+
.to.equal(true);
|
|
160
|
+
|
|
161
|
+
fTestComplete();
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
);
|