Bug 816730 - [Activities] Filters do not work anymore. r=mounir, sr=sicking

This commit is contained in:
Andrea Marchesini 2012-12-27 11:12:06 -05:00
parent 3c553a8b65
commit 11f00f17dc
8 changed files with 308 additions and 33 deletions

View File

@ -6,9 +6,12 @@ DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
PARALLEL_DIRS = interfaces src
TEST_DIRS += tests
include $(topsrcdir)/config/rules.mk

View File

@ -11,6 +11,7 @@ const Ci = Components.interfaces;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
Cu.import("resource://gre/modules/ActivitiesServiceFilter.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
@ -258,39 +259,8 @@ let Activities = {
};
let matchFunc = function matchFunc(aResult) {
function matchFuncValue(aValue, aFilter) {
// Bug 805822 - Regexp support for MozActivity
let values = Array.isArray(aValue) ? aValue : [aValue];
let filters = Array.isArray(aFilter) ? aFilter : [aFilter];
// At least 1 value must match.
let ret = false;
values.forEach(function(value) {
if (filters.indexOf(value) != -1) {
ret = true;
}
});
return ret;
}
// For any incoming property.
for (let prop in aMsg.options.data) {
// If this is unknown for the app, let's continue.
if (!(prop in aResult.description.filters)) {
continue;
}
// Otherwise, let's check the value against the filter.
if (!matchFuncValue(aMsg.options.data[prop], aResult.description.filters[prop])) {
return false;
}
}
return true;
return ActivitiesServiceFilter.match(aMsg.options.data,
aResult.description.filters);
};
this.db.find(aMsg, successCb, errorCb, matchFunc);

View File

@ -0,0 +1,127 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"
this.EXPORTED_SYMBOLS = ['ActivitiesServiceFilter'];
this.ActivitiesServiceFilter = {
match: function(aValues, aFilters) {
function matchValue(aValue, aFilter, aFilterObj) {
if (aFilter !== null) {
// Custom functions for the different types.
switch (typeof(aFilter)) {
case 'boolean':
return aValue === aFilter;
case 'number':
return Number(aValue) === aFilter;
case 'string':
return String(aValue) === aFilter;
default: // not supported
return false;
}
}
// Regexp.
if (('regexp' in aFilterObj)) {
var regexp = String(aFilterObj.regexp);
if (regexp[0] != "/")
return false;
var pos = regexp.lastIndexOf("/");
if (pos == 0)
return false;
var re = new RegExp(regexp.substring(1, pos), regexp.substr(pos + 1));
return re.test(aValue);
}
// Validation of the min/Max.
if (('min' in aFilterObj) || ('max' in aFilterObj)) {
// Min value.
if (('min' in aFilterObj) &&
aFilterObj.min > aValue) {
return false;
}
// Max value.
if (('max' in aFilterObj) &&
aFilterObj.max < aValue) {
return false;
}
}
return true;
}
// this function returns true if the value matches with the filter object
function matchObject(aValue, aFilterObj) {
// Let's consider anything an array.
let filters = ('value' in aFilterObj)
? (Array.isArray(aFilterObj.value)
? aFilterObj.value
: [aFilterObj.value])
: [ null ];
let values = Array.isArray(aValue) ? aValue : [aValue];
for (var filterId = 0; filterId < filters.length; ++filterId) {
for (var valueId = 0; valueId < values.length; ++valueId) {
if (matchValue(values[valueId], filters[filterId], aFilterObj)) {
return true;
}
}
}
return false;
}
// Creation of a filter map useful to know what has been
// matched and what is not.
let filtersMap = {}
for (let filter in aFilters) {
// Convert this filter in an object if needed
let filterObj = aFilters[filter];
if (Array.isArray(filterObj) || typeof(filterObj) !== 'object') {
filterObj = {
required: false,
value: filterObj
}
}
filtersMap[filter] = { filter: filterObj,
found: false };
}
// For any incoming property.
for (let prop in aValues) {
// If this is unknown for the app, let's continue.
if (!(prop in filtersMap)) {
continue;
}
// Otherwise, let's check the value against the filter.
if (!matchObject(aValues[prop], filtersMap[prop].filter)) {
return false;
}
filtersMap[prop].found = true;
}
// Required filters:
for (let filter in filtersMap) {
if (filtersMap[filter].filter.required && !filtersMap[filter].found) {
return false;
}
}
return true;
}
}

View File

@ -36,6 +36,7 @@ EXTRA_COMPONENTS = \
EXTRA_JS_MODULES = \
ActivitiesService.jsm \
ActivitiesServiceFilter.jsm \
$(NULL)
include $(topsrcdir)/config/config.mk

View File

@ -0,0 +1,17 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = @relativesrcdir@
FAIL_ON_WARNINGS := 1
include $(DEPTH)/config/autoconf.mk
XPCSHELL_TESTS = unit
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,151 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
Components.utils.import("resource:///modules/ActivitiesServiceFilter.jsm")
do_check_true(!!ActivitiesServiceFilter);
// No requests, no filters:
do_check_true(ActivitiesServiceFilter.match(null, null));
do_check_true(ActivitiesServiceFilter.match({}, {}));
// No filters:
do_check_true(ActivitiesServiceFilter.match({foobar: 42}, null));
// Empty request:
do_check_true(ActivitiesServiceFilter.match({}, {a: 'foobar', b: [1, 2, 3], c: 42}));
// Simple match:
do_check_true(ActivitiesServiceFilter.match({a: 'foobar'},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_false(ActivitiesServiceFilter.match({a: 'foobar', b: 2, c: true},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_true(ActivitiesServiceFilter.match({a: 'foobar', b: 2, c: 42},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_false(ActivitiesServiceFilter.match({a: 'foobar2'},
{a: 'foobar', b: [1, 2, 3], c: 42}));
// Simple match in array:
do_check_true(ActivitiesServiceFilter.match({b: 2},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_false(ActivitiesServiceFilter.match({b: 4},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_true(ActivitiesServiceFilter.match({b: [2, 4]},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_false(ActivitiesServiceFilter.match({b: [4, 5]},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_false(ActivitiesServiceFilter.match({a: [4, 'foobar2']},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_true(ActivitiesServiceFilter.match({a: [4, 'foobar']},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_true(ActivitiesServiceFilter.match({a: ['foo', 'bar']},
{a: 'foo'}));
// Unknown property
do_check_true(ActivitiesServiceFilter.match({k: 4},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_true(ActivitiesServiceFilter.match({k: [1,2,3,4]},
{a: 'foobar', b: [1, 2, 3], c: 42}));
// Required/non required
do_check_false(ActivitiesServiceFilter.match({},
{a: { required: true, value: 'foobar'}}));
do_check_true(ActivitiesServiceFilter.match({a: 'foobar'},
{a: { required: true, value: 'foobar'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'foobar2'},
{a: { required: true, value: 'foobar'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'foobar2'},
{a: { required: true, value: ['a', 'b', 'foobar']}}));
do_check_true(ActivitiesServiceFilter.match({a: 'foobar'},
{a: { required: true, value: ['a', 'b', 'foobar']}}));
do_check_true(ActivitiesServiceFilter.match({a: ['k', 'z', 'foobar']},
{a: { required: true, value: ['a', 'b', 'foobar']}}));
do_check_false(ActivitiesServiceFilter.match({a: ['k', 'z', 'foobar2']},
{a: { required: true, value: ['a', 'b', 'foobar']}}));
// Empty values
do_check_true(ActivitiesServiceFilter.match({a: 42},
{a: { required: true}}));
do_check_false(ActivitiesServiceFilter.match({},
{a: { required: true}}));
// Boolean
do_check_true(ActivitiesServiceFilter.match({a: false},
{a: { required: true, value: false}}));
do_check_false(ActivitiesServiceFilter.match({a: true},
{a: { required: true, value: false}}));
do_check_true(ActivitiesServiceFilter.match({a: [false, true]},
{a: { required: true, value: false}}));
do_check_true(ActivitiesServiceFilter.match({a: [false, true]},
{a: { required: true, value: [false,true]}}));
// Number
do_check_true(ActivitiesServiceFilter.match({a: 42},
{a: { required: true, value: 42}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, value: 42}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 1}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 2}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 3}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, max: 1}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, max: 2}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, max: 3}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 1, max: 1}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 1, max: 2}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 2, max: 2}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, value: 'foo'}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 100, max: 0}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 'a', max: 'b'}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 10, max: 1}}));
// String
do_check_true(ActivitiesServiceFilter.match({a: 'foo'},
{a: { required: true, value: 'foo'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'foo2'},
{a: { required: true, value: 'foo'}}));
// Number VS string
do_check_true(ActivitiesServiceFilter.match({a: '42'},
{a: { required: true, value: 42}}));
do_check_true(ActivitiesServiceFilter.match({a: 42},
{a: { required: true, value: '42'}}));
do_check_true(ActivitiesServiceFilter.match({a: '-42e+12'},
{a: { required: true, value: -42e+12}}));
do_check_true(ActivitiesServiceFilter.match({a: 42},
{a: { required: true, min: '1', max: '50'}}));
do_check_true(ActivitiesServiceFilter.match({a: '42'},
{a: 42 }));
do_check_true(ActivitiesServiceFilter.match({a: 42},
{a: '42' }));
do_check_false(ActivitiesServiceFilter.match({a: 42},
{a: { min: '44' }}));
do_check_false(ActivitiesServiceFilter.match({a: 42},
{a: { max: '0' }}));
// String + RegExp
do_check_true(ActivitiesServiceFilter.match({a: 'foobar'},
{a: { required: true, regexp: '/^foobar/'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'aafoobar'},
{a: { required: true, regexp: '/^foobar/'}}));
do_check_true(ActivitiesServiceFilter.match({a: 'aaFOOsdsad'},
{a: { required: true, regexp: '/foo/i'}}));
do_check_true(ActivitiesServiceFilter.match({a: 'aafoobarasdsad'},
{a: { required: true, regexp: '/foo/'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'aaFOOsdsad'},
{a: { required: true, regexp: '/foo/'}}));
}

View File

@ -0,0 +1,5 @@
[DEFAULT]
head =
tail =
[test_activityFilters.js]

View File

@ -9,6 +9,7 @@
[include:uriloader/exthandler/tests/unit/xpcshell.ini]
[include:parser/xml/test/unit/xpcshell.ini]
[include:image/test/unit/xpcshell.ini]
[include:dom/activities/tests/unit/xpcshell.ini]
[include:dom/encoding/test/unit/xpcshell.ini]
[include:dom/plugins/test/unit/xpcshell.ini]
[include:dom/sms/tests/xpcshell.ini]