Skip to content

Instantly share code, notes, and snippets.

@lovasoa
Last active December 17, 2015 10:39
Show Gist options
  • Save lovasoa/5596203 to your computer and use it in GitHub Desktop.
Save lovasoa/5596203 to your computer and use it in GitHub Desktop.
This little utility allows me to test an API (kind of fuzzing it). Starting from a json request that I know is working, it reduces it (by removing properties) until the json object isn't a valid API call anymore.

inputReducer.js

Description

This little utility allows me to test an API (kind of fuzzing it). Starting from a big json request that I know is working, it reduces it (by removing properties) until the json object isn't a valid API call anymore.

How to use

reduceInput(
	bigWorkingObj,
	function(semiReduced, callback){
		callAPIasync(semiReduced, function(error, result){
			if (error) callback(false);
			else callback(true);
		});
	},
	function(reduced){
		console.log("The minimal valid request is: ",reduced);
	}
);
Mfunction objcopy(obj) {
if (Array.isArray(obj)) {
return obj.slice(0);
} else if (typeof (obj) === "object") {
var newobj = {};
for (var key in obj) { newobj[key] = objcopy(obj[key]); }
return newobj;
} else {
return obj;
}
}
function getSubObj (obj, key) {
var tmpobj = obj;
for (var i=0; i<key.length; i++) {
if (typeof (tmpobj[key[i]]) === "object" || i===key.length-1) {
tmpobj = tmpobj[key[i]];
} else {
throw new Error("Invalid key");
}
}
return tmpobj;
}
function deleteKey (obj, key) {
var subobj = getSubObj(obj, key.slice(0,-1));
var ret = subobj[key[key.length-1]];
delete subobj[key[key.length-1]];
return ret;
}
function insertKey (obj, key, value) {
var tmp = obj;
for (var i=0; i<key.length-1; i++) {
if (typeof (tmp[key[i]]) !== "object"){
tmp[key[i]] = {};
}
tmp = tmp[key[i]];
}
tmp[key[i]] = value;
return obj;
}
function firstKey (obj) {
if (typeof (obj) === "object") {
var key = Object.keys(obj).sort()[0];
if (key === undefined) {
return [];
} else {
return [key].concat(firstKey(obj[key]))
}
} else {
return [];
}
}
function nextKey (obj, key) {
if (key === undefined) return firstKey(obj);
var subkey = key.slice();
do {
var lastPartOfKey = subkey.pop();
//The key was the last key in the object
if (lastPartOfKey === undefined) return null;
var subobj = getSubObj(obj, subkey);
var keys = Object.keys(subobj).sort();
var index = keys.indexOf(lastPartOfKey);
if (index === -1) throw new Error("Invalid key");
} while (index === keys.length-1);
return subkey.concat(keys[index+1], firstKey(subobj[keys[index+1]]));
}
function reduceInput(input, testfunc, testFinishedCallback) {
var key, ret=objcopy(input), waitingCallbacks=0, finished=false;
while (1) {
var key = nextKey(input, key);
if (key === null) break;
var removed = deleteKey(input, key);
(function(){
var thisKey = key;
try {
waitingCallbacks++;
var testresult = testfunc(input, function(testpassed){
//If the test still passes even without the key, we can remove it
if (testpassed) {
deleteKey(ret, thisKey);
}
waitingCallbacks--;
if (waitingCallbacks===0 && finished===true) {
testFinishedCallback(ret);
}
});
} catch (e) {}
})();
insertKey(input, key, removed);
}
finished = true;
if (waitingCallbacks===0) {
testFinishedCallback (ret);
}
}
/*
//Exemple :
var obj={a:{b:[1,2]},c:[0]};
reduceInput(
obj,
function(red, callb){
var ret = typeof(red.a.b[0])==="number";
console.log(red, ret);
callb(ret);
},
function(reduced){
console.log("obj",obj,"reduced",reduced);
}
);
*/
if (exports) {
exports.reduceInput = reduceInput;
exports.nextKey = nextKey;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment