add more unit tests to uci (coverage at 71%)

This commit is contained in:
Martin Schröder 2016-12-15 12:44:13 +01:00
parent ba7c7a2b5b
commit affdcc9785
2 changed files with 192 additions and 82 deletions

View File

@ -6,6 +6,13 @@ global.async = require("async");
global.watch = require("watchjs").watch;
global.expect = require("expect.js");
*/
// simulated config database
var CONFIG = {
test: {
}
};
global.gettext = function(str) { return str; }
global.assert = require("assert");
global.async = require("async");
@ -16,32 +23,69 @@ global.UBUS = {
console.log("UCI get");
var def = $.Deferred();
setTimeout(function(){
def.resolve({
values: {
".name": "mysection",
".type": "test",
field: "foo"
}
});
var conf = CONFIG[params.config];
if(conf && !params.section){
def.resolve({
values: conf
});
} else if(conf && params.section && conf[params.section]){
def.resolve({
values: conf[params.section]
});
} else {
def.reject();
}
}, 0);
return def.promise();
},
set: function(params){
console.log("UCI add");
console.log("UCI set");
var def = $.Deferred();
setTimeout(function(){
def.resolve({
});
if(!params.config || !params.section || !params.values) {
console.error("RPC: INVALID PARAMETERS TO UCI SET!");
def.reject();
return;
}
var conf = CONFIG[params.config];
if(conf && conf[params.section]){
var s = conf[params.section];
Object.keys(params.values).map(function(x){
s[x] = params.values[x];
});
def.resolve({});
} else {
def.reject();
}
}, 0);
return def.promise();
},
add: function(params){
console.log("UCI add");
console.log("UCI ADD: "+JSON.stringify(params));
var def = $.Deferred();
setTimeout(function(){
def.resolve({
section: params["name"] || "unknown"
});
if(!params.config || !params.type) {
console.error("INVALID ARGUMENTS TO UCI.add!");
def.reject();
return;
}
var conf = CONFIG[params.config];
if(conf && conf[params["name"]] != undefined){
console.error("SECTION ALREADY EXISTS");
def.reject();
} else {
var name = (params.name)?params.name:String((new Date()).getTime());
var obj = {};
Object.keys(params.values).map(function(x){
obj[x] = params.values[x];
});
obj[".name"] = name;
obj[".type"] = params.type;
conf[name] = obj;
def.resolve({
section: name
});
}
}, 0);
return def.promise();
},
@ -54,11 +98,11 @@ global.UBUS = {
return def.promise();
},
configs: function(){
console.log("UCI add");
console.log("UCI configs");
var def = $.Deferred();
setTimeout(function(){
def.resolve({
configs: [ "test" ]
configs: Object.keys(CONFIG)
});
}, 0);
return def.promise();
@ -72,12 +116,14 @@ UCI.$registerConfig("test");
UCI.test.$registerSectionType("test", {
"field": { dvalue: "test", type: String },
"string": { dvalue: "test", type: String },
"number": { dvalue: 3.14, type: Number },
"array": { dvalue: [], type: Array },
"ip4field": { dvalue: "test", type: String, validator: UCI.validators.IP4AddressValidator },
"time": { dvalue: "00:00", type: String, validator: UCI.validators.TimeValidator },
"timespan": { dvalue: "00:00-01:00", type: String, validator: UCI.validators.TimespanValidator },
"weekdays": { dvalue: [], type: String, validator: UCI.validators.WeekDayListValidator },
"weekdays": { dvalue: [], type: Array, validator: UCI.validators.WeekDayListValidator },
"portrange": { dvalue: "", type: String, validator: UCI.validators.PortValidator },
"minmax": { dvalue: "", type: String, validator: UCI.validators.NumberLimitValidator(0, 100) },
"minmax": { dvalue: "", type: Number, validator: UCI.validators.NumberLimitValidator(0, 100) },
"multicast": { dvalue: "", type: String, validator: UCI.validators.IP4MulticastAddressValidator },
"unicast": { dvalue: "", type: String, validator: UCI.validators.IP4UnicastAddressValidator },
"ip4cidr": { dvalue: "", type: String, validator: UCI.validators.IP4CIDRValidator },
@ -85,9 +131,12 @@ UCI.test.$registerSectionType("test", {
"ipcidr": { dvalue: "", type: String, validator: UCI.validators.IPCIDRAddressValidator },
"ip4mask": { dvalue: "", type: String, validator: UCI.validators.IP4NetmaskValidator },
"mac": { dvalue: "", type: String, validator: UCI.validators.MACAddressValidator },
"maclist": { dvalue: [], type: String, validator: UCI.validators.MACListValidator },
"array": { dvalue: [], type: String, validator: UCI.validators.ArrayValidator(UCI.validators.IP4AddressValidator) },
"maclist": { dvalue: [], type: Array, validator: UCI.validators.MACListValidator },
"iparray": { dvalue: [], type: Array, validator: UCI.validators.ArrayValidator(UCI.validators.IP4AddressValidator) },
"bool": { dvalue: false, type: Boolean },
"boolyesno": { dvalue: "yes", type: Boolean },
"boolonoff": { dvalue: "on", type: Boolean },
"booltf": { dvalue: "true", type: Boolean },
});
describe("init", function(){
@ -125,21 +174,29 @@ describe("Section operations", function(){
});
it("add a new section with invalid type", function(done){
assert(UCI.test.mysection);
try {
UCI.test.$create({
".name": "mysection",
".type": "noexist"
}).done(function(){
done(new Error("Able to create invlid sections"));
throw new Error("Able to create invalid sections");
done();
}).fail(function(){
done(new Error("unable to create section"));
throw new Error("unable to create section");
done();
});
} catch(err){
console.error("ERROR: "+err);
done();
}
});
it("saves a section", function(done){
// first check here that we indeed have mysection in all the correct places
assert(UCI.test.mysection);
assert.equal(UCI.test["@test"][0][".name"], "mysection");
assert.equal(UCI.test["@all"][0][".name"], "mysection");
UCI.$save().done(function(){
done();
});
@ -149,23 +206,46 @@ describe("Section operations", function(){
UCI.test.mysection.field.value = "newstuff";
assert.equal(UCI.$hasChanges(), true);
var changes = UCI.$getChanges();
assert.equal(changes.find(function(x){
return x.config == "test" && x.section == "mysection" && x.field == "field";
}).value, "newstuff");
console.log(JSON.stringify(changes));
var change = changes.find(function(x){
return x.config == "test" && x.section == "mysection" && x.option == "field";
});
assert(change);
assert.equal(change.uvalue, "newstuff");
UCI.$save().done(function(){
done();
});
});
/**
* This test tests that reloading works correctly. Values changed by the
* user should be preserved while values changed on the backend that are
* not changed by the user should be updated. If reload is passed "false"
* as argument then all values shall be updated.
*/
it("reload a section", function(done){
var f = UCI.test.mysection.field;
f.value = "reload";
// reload needs to be tested with a mock version of data and we need to establish reload rules
UCI.test.$reload(false).done(function(){
assert(f.value != "reload");
done();
var s = UCI.test.mysection;
s.field.value = "reload";
// first try modifying it and reloading only user changes
assert(CONFIG.test.mysection.field != "foobar");
assert(CONFIG.test.mysection.string != "changed");
CONFIG.test.mysection.field = "foobar";
CONFIG.test.mysection.string = "changed";
UCI.test.$reload(true).done(function(){
// result should be that field will not be reloaded but string will change
assert(UCI.test.mysection);
assert(s.field.value == "reload");
assert(s.string.value == "changed");
// reload needs to be tested with a mock version of data and we need to establish reload rules
UCI.test.$reload(false).done(function(){
assert(UCI.test.mysection);
assert(s.field.value != "reload");
done();
}).fail(function(){
assert.equals(false, "failed to reload section");
done();
});
}).fail(function(){
assert.equals(false, "failed to reload section");
done();
});
});
@ -178,18 +258,20 @@ describe("Section operations", function(){
assert(f.value == "newstuff2");
UCI.test.$reset();
assert(f.value != "newstuff2");
assert(UCI.test.mysection);
done();
});
});
describe("Field operations", function(){
it("try setting different values", function(done){
assert(UCI.test.mysection);
UCI.test.$create({
".name": "another",
".type": "test",
"field": "value"
}).done(function(){
var s = UCI.test["@test"][0];
var s = UCI.test.another;
assert.equal(s.field.value, "value");
s.field.value = "me";
assert.equal(s.field.value, "me");
@ -201,19 +283,34 @@ describe("Field operations", function(){
done(new Error("unable to create section"));
});
});
it("string field", function(done){
it("check that fields can not be set to values of different type than the field itself", function(){
var s = UCI.test.mysection;
s.string.value = "anystring";
assert.equal(s.string.value, "anystring");
s.string.value = false;
s.string.value = 0;
s.string.value = 123.4;
s.string.value = [];
assert.equal(s.string.value, "anystring");
s.number.value = 1234;
assert.equal(s.number.value, 1234);
s.number.value = "";
s.number.value = false;
s.number.value = true;
s.number.value = [];
assert.equal(s.number.value, 1234);
s.array.value = [1, 2, 3, 4];
assert.equal(s.array.value[3], 4);
s.array.value = "test";
s.array.value = 123;
s.array.value = false;
s.array.value = true;
assert.equal(s.array.value[3], 4);
});
it("string field", function(){
var s = UCI.test["@test"][0];
assert.equal(UCI.$getErrors().length, 0);
s.string.value = ["24:00"];
assert(UCI.$getErrors().length, 1);
s.string.value = [{}];
assert.equal(UCI.$getErrors().length, 1);
s.string.value = {};
assert.equal(UCI.$getErrors().length, 1);
s.string.value = 0;
assert.equal(UCI.$getErrors().length, 1);
s.string.value = 1.4;
assert.equal(UCI.$getErrors().length, 1);
s.string.value = "24:00";
assert.equal(UCI.$getErrors().length, 0);
});
@ -319,11 +416,6 @@ describe("Field operations", function(){
it("number limit", function(){
var s = UCI.test["@test"][0];
assert.equal(UCI.$getErrors().length, 0);
s.minmax.value = "0";
assert.equal(UCI.$getErrors().length, 0);
s.minmax.value = "-1";
assert.equal(UCI.$getErrors().length, 1);
s.minmax.value = -1;
assert.equal(UCI.$getErrors().length, 1);
s.minmax.value = 101;
@ -473,31 +565,42 @@ describe("Field operations", function(){
it("ip array", function(){
var s = UCI.test["@test"][0];
assert.equal(UCI.$getErrors().length, 0);
s.array.value = "asdf"; // value will not be set because array is expected
s.iparray.value = "asdf"; // value will not be set because array is expected
assert.equal(UCI.$getErrors().length, 0);
assert(s.array.value.length == 0);
s.array.value = ["20.10.30.4", "10.20.30.40"];
assert(s.array.value.length == 2);
assert(s.iparray.value.length == 0);
s.iparray.value = ["20.10.30.4", "10.20.30.40"];
assert(s.iparray.value.length == 2);
assert.equal(UCI.$getErrors().length, 0);
});
it("boolean ops", function(){
var s = UCI.test["@test"][0];
assert.equal(UCI.$getErrors().length, 0);
var prev = s.bool.value;
s.bool.value = "asdf";
assert.equal(UCI.$getErrors().length, 1);
s.bool.value = "on";
assert(s.bool.value == true);
assert(UCI.$getErrors().length == 0);
s.bool.value = "off";
assert(s.bool.value == false && UCI.$getErrors().length == 0);
s.bool.value = "yes";
assert(s.bool.value == true && UCI.$getErrors().length == 0);
s.bool.value = "no";
assert(s.bool.value == false && UCI.$getErrors().length == 0);
s.bool.value = "true";
assert(s.bool.value == true && UCI.$getErrors().length == 0);
s.bool.value = "false";
assert(s.bool.value == false && UCI.$getErrors().length == 0);
assert(s.bool.value == prev);
//assert.equal(UCI.$getErrors().length, 1);
s.bool.value = true;
s.boolonoff.value = true;
s.boolyesno.value = true;
s.booltf.value = true;
UCI.$save().done(function(){
var conf = CONFIG.test[s[".name"]];
assert.equal(conf.bool, true);
assert.equal(conf.boolonoff, "on");
assert.equal(conf.boolyesno, "yes");
assert.equal(conf.booltf, "true");
s.bool.value = false;
s.boolonoff.value = false;
s.boolyesno.value = false;
s.booltf.value = false;
UCI.$save().done(function(){
assert.equal(conf.bool, false);
assert.equal(conf.boolonoff, "off");
assert.equal(conf.boolyesno, "no");
assert.equal(conf.booltf, "false");
});
});
});
});

View File

@ -330,21 +330,21 @@
// set dirty if not same
var self = this;
self.__value_error = null;
if((typeof val != typeof this.schema.type()) || (val instanceof Array && !(self.ovalue instanceof Array))) {
// make sure that for all of our types the value is of valid type as well
if( (self.schema.type == Number && typeof val != "number") ||
(self.schema.type == String && typeof val != "string") ||
(self.schema.type == Array && (val.length == undefined || !(val instanceof Array)))){ // TODO: maybe do better identification of arrays (they appear as objects)
//self.__value_error = gettext("Field has been set to value of a different type than what was defined in the schema!");
//return;
}
if(self.schema.dvalue instanceof String && !(val instanceof String)){
//self.__value_error = gettext("Field has been set to value of a different type than what was defined in the schema!");
//return;
return;
}
if(val instanceof Array){
// our arrays never contain objects so we can do this
self.is_dirty = JSON.stringify(val) != JSON.stringify(self.uvalue);
} else {
self.is_dirty = val != self.ovalue;
}
if(self.ovalue instanceof Array && !(val instanceof Array)) return;
if(val instanceof Array && self.ovalue instanceof Array){
self.is_dirty = false;
if(val.length != self.ovalue.length) self.is_dirty = true;
@ -353,13 +353,18 @@
// properly handle booleans
if(this.schema.type == Boolean){
if(this.ovalue == "on" || this.ovalue == "off") { this.uvalue = (val)?"on":"off"; }
else if(this.ovalue == "yes" || this.ovalue == "no") { this.uvalue = (val)?"yes":"no"; }
else if(this.ovalue == "true" || this.ovalue == "false") { this.uvalue = (val)?"true":"false"; }
else if(this.ovalue == true || this.ovalue == false){
var val = null;
if(this.ovalue != undefined) val = this.ovalue;
else if(this.dvalue != undefined) val = this.dvalue;
if(["on", "off"].indexOf(val) != -1) { this.uvalue = (val)?"on":"off"; }
else if(["yes", "no"].indexOf(val) != -1) { this.uvalue = (val)?"yes":"no"; }
else if(["true", "false"].indexOf(val) != -1) { this.uvalue = (val)?"true":"false"; }
else if([true, false].indexOf(val) != -1 && typeof val == "boolean"){
this.uvalue = val;
} else {
this.__value_error = gettext("Invalid boolean value");
//this.__value_error = gettext("Invalid boolean value");
return;
}
} else {
if(val instanceof Array) {
@ -710,7 +715,8 @@
Object.keys(self).map(function(x){
if(self[x] && self[x].constructor == UCI.Section){
self[x].$reset();
if(self[x][".new"]) self[x].$delete();
// TODO: this should be made to work such that if we reset we only delete sections that have not been commited yet
//if(self[x][".new"]) self[x].$delete();
}
});
self[".need_commit"] = false;
@ -832,6 +838,7 @@
}
// set object values on objects that match search criteria
// if object does not exist, then create a new object
/** TODO: where is this used exactly?
UCIConfig.prototype.set = function(search, values){
var self = this;
self["@all"].map(function(item){
@ -843,7 +850,7 @@
}
});
}
**/
UCIConfig.prototype.$registerSectionType = function(name, descriptor, validator){
var config = this[".name"];
var conf_type = section_types[config];
@ -928,7 +935,7 @@
}, 0);
return deferred.promise();
}
console.log("Adding: "+JSON.stringify(item)+" to "+self[".name"]+": "+JSON.stringify(values));
$rpc.uci.add({
"config": self[".name"],