From 6cfd142a3f9a6bdb0f74d433a2f9a3b1fba92ef0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 25 Nov 2017 11:15:10 -0800 Subject: [PATCH] Add entity filter --- src/common/entity/entity_filter.js | 62 +++++++++++++++++ test-mocha/common/util/entity_filter.js | 88 +++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 src/common/entity/entity_filter.js create mode 100644 test-mocha/common/util/entity_filter.js diff --git a/src/common/entity/entity_filter.js b/src/common/entity/entity_filter.js new file mode 100644 index 000000000000..955ccc63ca19 --- /dev/null +++ b/src/common/entity/entity_filter.js @@ -0,0 +1,62 @@ +import computeDomain from "./compute_domain.js"; + +export function generateFilter( + includeDomains = [], + includeEntities = [], + excludeDomains = [], + excludeEntities = [] +) { + includeDomains = new Set(includeDomains); + includeEntities = new Set(includeEntities); + excludeDomains = new Set(excludeDomains); + excludeEntities = new Set(excludeEntities); + + const haveInclude = includeDomains.size | (includeEntities.size !== 0); + const haveExclude = excludeDomains.size | (excludeEntities.size !== 0); + + // Case 1 - no includes or excludes - pass all entities + if (!haveInclude && !haveExclude) { + return () => true; + } + + // Case 2 - includes, no excludes - only include specified entities + if (haveInclude && !haveExclude) { + return (entityId) => + includeEntities.has(entityId) || + includeDomains.has(computeDomain(entityId)); + } + + // Case 3 - excludes, no includes - only exclude specified entities + if (!haveInclude && haveExclude) { + return (entityId) => + !excludeEntities.has(entityId) && + !excludeDomains.has(computeDomain(entityId)); + } + + // Case 4 - both includes and excludes specified + // Case 4a - include domain specified + // - if domain is included, and entity not excluded, pass + // - if domain is not included, and entity not included, fail + // note: if both include and exclude domains specified, + // the exclude domains are ignored + if (includeDomains.size) { + return (entityId) => + includeDomains.has(computeDomain(entityId)) + ? !excludeEntities.has(entityId) + : includeEntities.has(entityId); + } + + // Case 4b - exclude domain specified + // - if domain is excluded, and entity not included, fail + // - if domain is not excluded, and entity not excluded, pass + if (excludeDomains.size) { + return (entityId) => + excludeDomains.has(computeDomain(entityId)) + ? includeEntities.has(entityId) + : !excludeEntities.has(entityId); + } + + // Case 4c - neither include or exclude domain specified + // - Only pass if entity is included. Ignore entity excludes. + return (entityId) => includeEntities.has(entityId); +} diff --git a/test-mocha/common/util/entity_filter.js b/test-mocha/common/util/entity_filter.js new file mode 100644 index 000000000000..bcccfb05f9c9 --- /dev/null +++ b/test-mocha/common/util/entity_filter.js @@ -0,0 +1,88 @@ +import { generateFilter } from "../../../src/common/entity/entity_filter.js"; + +const assert = require("assert"); + +describe("EntityFilter", () => { + // case 1 + it("passes all when no filters passed in", () => { + const filter = generateFilter(); + + assert(filter("sensor.test")); + assert(filter("sun.sun")); + assert(filter("light.test")); + }); + + // case 2 + it("allows whitelisting entities by entity id", () => { + const filter = generateFilter(null, ["light.kitchen"]); + + assert(filter("light.kitchen")); + assert(!filter("light.living_room")); + }); + + it("allows whitelisting entities by domain", () => { + const filter = generateFilter(["switch"]); + + assert(filter("switch.bla")); + assert(!filter("light.kitchen")); + }); + + // case 3 + it("allows blacklisting entities by entity id", () => { + const filter = generateFilter(null, null, null, ["light.kitchen"]); + + assert(!filter("light.kitchen")); + assert(filter("light.living_room")); + }); + + it("allows blacklisting entities by domain", () => { + const filter = generateFilter(null, null, ["switch"]); + + assert(!filter("switch.bla")); + assert(filter("light.kitchen")); + }); + + // case 4a + it("allows whitelisting domain and blacklisting entity", () => { + const filter = generateFilter(["switch"], null, null, ["switch.kitchen"]); + + assert(filter("switch.living_room")); + assert(!filter("switch.kitchen")); + assert(!filter("sensor.bla")); + }); + + it("allows whitelisting entity while whitelisting other domains", () => { + const filter = generateFilter(["switch"], ["light.kitchen"]); + + assert(filter("switch.living_room")); + assert(filter("light.kitchen")); + assert(!filter("sensor.bla")); + }); + + // case 4b + it("allows blacklisting domain and whitelisting entity", () => { + const filter = generateFilter(null, ["switch.kitchen"], ["switch"]); + + assert(filter("switch.kitchen")); + assert(!filter("switch.living_room")); + assert(filter("sensor.bla")); + }); + + it("allows blacklisting domain and excluding entities", () => { + const filter = generateFilter(null, null, ["switch"], ["light.kitchen"]); + + assert(!filter("switch.living_room")); + assert(!filter("light.kitchen")); + assert(filter("sensor.bla")); + }); + + // case 4c + it("allows whitelisting entities", () => { + const filter = generateFilter(null, ["light.kitchen"]); + + assert(filter("light.kitchen")); + assert(!filter("switch.living_room")); + assert(!filter("light.living_room")); + assert(!filter("sensor.bla")); + }); +});