---
base:
'#initialize': [
[
'MUST initialize',
[],
[[], {}]
]
]
'#clear': [
[
'MUST clear the root',
[
['set', '/setup/driver/uuid', 'cc88b93a-3556-4e44-9b81-c45aa1ba9604'],
['set', '/setup/driver/connected', true],
['clear']
],
[[], {}]
]
]
'#set': [
[
'MUST set a single value "/a", true',
[
['set', '/a', true]
],
[['a'], true]
],
[
'MUST set a single value "/a/b", true',
[
['set', '/a/b', true]
],
[['a', 'b'], true]
],
[
'MUST set a single value "/a/b/c", true',
[
['set', '/a/b/c', true]
],
[['a', 'b', 'c'], true]
]
]
'#get': [
[
'MUST return a #set value at a path',
[['set', '/setup/driver/uuid', 'cc88b93a-3556-4e44-9b81-c45aa1ba9604']],
['get', '/setup/driver/uuid', 'cc88b93a-3556-4e44-9b81-c45aa1ba9604']
],
[
'MUST return nil for a #delete(d) value at a path',
[
['set', '/setup/driver/uuid', 'cc88b93a-3556-4e44-9b81-c45aa1ba9604'],
['delete', '/setup/driver/uuid']
],
['get', '/setup/driver/uuid', undefined]
]
]
'#delete': [
[
'MUST set a single value "/a", true',
[
['set', '/a', true],
['delete', '/a']
],
[[], {}]
],
[
'MUST delete a single value "/a/b", true',
[
['set', '/a/b', true],
['delete', '/a/b']
],
[[], {}]
],
[
'MUST delete a single value "/a/b/c", true',
[
['set', '/a/b/c', true],
['delete', '/a/b/c']
],
[[], {}]
],
[
'MUST not clear the root when deleting a root key',
[
['set', '/a1', true],
['set', '/a2', true],
['delete', '/a2']
],
[[], { 'a1': true }]
]
]
convenience:
'#each': [
[
'MUST call with the elements of an array',
[['each', '/setup/rooms/1/area_paths']],
['/areas/1', '/areas/2']
]
]
'#has': [
['MUST return false when path does not exist', ['has', '/setup/areas/2'], false],
['MUST return true when path does exist', ['has', '/setup/rooms/1/name'], true],
['MUST return true when path does exist but is an empty hash', ['has', '/setup/components'], true]
]
'#includes': [
['MUST return true if the found array has a value', ['includes', '/setup/rooms/1/area_paths', '/areas/1'], true],
['MUST return false if the found value is not an array', ['includes', '/setup/areas/1', '/rooms/11'], false],
['MUST return false if the found array does not have a value', ['includes', '/setup/areas/1/room_paths', '/rooms/11'], false]
]
'#any': [
['MUST return true if node is a hash and is not empty', ['any', '/setup/rooms/1'], true],
['MUST return false if node is an empty hash', ['any', '/setup/drivers'], false],
['MUST return false if node is an array', ['any', '/setup/areas/1/room_paths'], false],
['MUST return false if node is an empty hash', ['any', '/setup/areas/1/name'], false]
]
'#keys': [
['MUST return an array of the keys at a node', ['keys', '/setup/rooms'], ['1', '2']],
['MUST return an empty array if the node is primitive', ['keys', '/setup/areas/1/name'], []],
['MUST return an empty array if the node is an array', ['keys', '/setup/areas/1/room_paths'], []]
]
'#branchPaths': [
['MUST return branch paths that exist at a passed path', ['branchPaths', '/setup/components/1'], ['/components/1', '/components/1/displays/1']]
]
'#push': [
[
"'/setup/rooms/2/area_paths', '/areas/2'",
[['push', '/setup/rooms/1/area_paths', '/areas/2']],
[['/setup/rooms/1/area_paths', ['/areas/1', '/areas/2']]]
]
]
'#pull': [
[
"'/setup/rooms/2/area_paths', '/areas/2'",
[['pull', '/setup/rooms/1/area_paths', '/areas/2']],
[['/setup/rooms/1/area_paths', ['/areas/1']]]
]
]
'#add': [
[
"'/setup/rooms', { name: 'Dining Room' }",
[['add', '/setup/rooms', { 'name': 'Dining Room'}]],
[['/setup/rooms/3', { 'name': 'Dining Room' }]]
],
[
"'/setup/components', { 'name': 'Component 3' }",
[['add', '/setup/components', { 'name': 'Component 3'}]],
[['/setup/components/3', { 'name': 'Component 3' }]]
]
]
external:
'#read': [
[
'MUST read a datastore node when passed a standard topic, "/setup"',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room']
],
['read', '/setup', { 'rooms': { '1': { 'name': 'Kitchen' }, '2': { 'name': 'Breakfast Room' }}}]
],
[
'MUST read a coppiced datastore node when passed a standard topic "/setup" and { coppiced: true }',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room']
],
['read', '/setup', { coppiced: true }, { '/setup/rooms/1/name': 'Kitchen', '/setup/rooms/2/name': 'Breakfast Room' }]
],
[
'MUST read a coppiced datastore node when passed a MQTT topic, "/setup/rooms/+/name"',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room']
],
['read', '/setup/rooms/+/name', { '/setup/rooms/1/name': 'Kitchen', '/setup/rooms/2/name': 'Breakfast Room' }]
],
[
'MUST read a coppiced datastore node when passed a standard topic "/setup/rooms/+/name" and { coppiced: true }',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room']
],
['read', '/setup/rooms/+/name', { coppiced: true }, { '/setup/rooms/1/name': 'Kitchen', '/setup/rooms/2/name': 'Breakfast Room' }]
],
[
'MUST return an empty value when MQTT topic is deeper than existing data "/setup/rooms/+/+/#"',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room']
],
['read', '/setup/rooms/+/+/#', {}]
],
[
'MUST return an empty value when MQTT topic is deeper than existing data "/setup/rooms/+/+/+"',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room']
],
['read', '/setup/rooms/+/+/+', {}]
],
[
'MUST return an empty value when MQTT topic is deeper than existing data "/setup/rooms/+/+/*"',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room']
],
['read', '/setup/rooms/+/+/*', {}]
],
[
'MUST read a coppiced datastore node when passed a MQTT topic, "systems/local/setup/components/+/displays/+/name"',
[],
['read', 'systems/local/setup/components/+/displays/+/name', {
'/systems/local/setup/components/1/displays/1/name': 'Kitchen Display',
'/systems/local/setup/components/2/displays/1/name': 'Breakfast Room Display'
}]
]
]
'#search': [
[
'MUST find a single matched primitive from a standard topic "setup/rooms/1/name"',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room']
],
['search', 'setup/rooms/1/name', { '/setup/rooms/1/name': 'Kitchen' }]
],
[
'MUST find a multiple matched primitives from a MQTT topic "setup/rooms/+/name"',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room']
],
['search', 'setup/rooms/+/name', { '/setup/rooms/1/name': 'Kitchen', '/setup/rooms/2/name': 'Breakfast Room' }]
],
[
'MUST find a multiple matched primitives from a MQTT topic "setup/rooms/#"',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room']
],
['search', 'setup/rooms/#', { '/setup/rooms/1/name': 'Kitchen', '/setup/rooms/2/name': 'Breakfast Room' }]
]
]
'#write': [
[
'MUST overwrite a datastore node "setup/rooms/1/name"',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room'],
['write', '/setup/rooms', { '1': { 'name': 'Dining Room' }}]
],
['read', 'setup/rooms', { '1': { 'name': 'Dining Room' } }]
]
]
'#merge': [
[
'MUST integrate value paths in a datastore node setup/rooms/1/name',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Breakfast Room'],
['merge', '/setup/rooms', { '3': { 'name': 'Dining Room' } }]
],
['read', 'setup/rooms', { '1': { 'name': 'Kitchen' }, '2': { 'name': 'Breakfast Room' }, '3': { 'name': 'Dining Room' } }]
],
[
'MUST set values to a new node',
[
['merge', '/state/components/1/calendars/1/update/organizer/email', 'spec@controlenvy.com']
],
['read', '/state/components/1/calendars/1/update/organizer/email', 'spec@controlenvy.com']
],
[
'MUST overwrite primitive values',
[
['merge', '/state/components/1/calendars/1/update/organizer/email', 'rspec@controlenvy.com'],
['merge', '/state/components/1/calendars/1/update/organizer/email', 'spec@controlenvy.com']
],
['read', '/state/components/1/calendars/1/update/organizer/email', 'spec@controlenvy.com']
],
[
'MUST overwrite primitive values',
[
['merge', '/state/components/1/calendars/1/update/organizer/email', 'spec@controlenvy.com'],
['merge', '/state/components/1/calendars/1/update/organizer', 'controlenvy']
],
['read', '/state/components/1/calendars/1/update/organizer', 'controlenvy']
],
[
'MUST overwrite nodes when the path becomes a primitive value',
[
['merge', '/state/components/1/calendars/1/update/organizer/email', 'spec@controlenvy.com'],
['merge', '/state/components/1/calendars/1/update/organizer', 'controlenvy']
],
['read', '/state/components/1/calendars/1/update/organizer', 'controlenvy']
],
[
'MUST overwrite primitive values when the path becomes a node',
[
['merge', '/state/components/1/calendars/1/update/organizer', 'controlenvy'],
['merge', '/state/components/1/calendars/1/update/organizer/email', 'spec@controlenvy.com']
],
['read', '/state/components/1/calendars/1/update/organizer', { 'email': 'spec@controlenvy.com' }]
]
]
pubsub:
'#topic_tree': [
[
'MUST add MQTT topics to the topic tree "state/components/+/status"',
[
['subscribe', 'state/components/+/status', '#subscriber', '#callback']
],
[['state/components/1/status', 'state/components/+/status', '#subscriber']]
],
[
'MUST remove MQTT topic from the topic tree "state/components/+/status"',
[
['subscribe', 'state/components/+/status', '#subscriber', '#callback'],
['unsubscribe', 'state/components/+/status', '#subscriber', '#callback']
],
[['state/components/1/status', null]]
],
[
'MUST not affect other subscribers when identical topic is removed from the topic tree',
[
['subscribe', 'state/components/1/status', '#subscriber_1', '#callback'],
['subscribe', 'state/components/1/status', '#subscriber_2', '#callback'],
['unsubscribe', 'state/components/1/status', '#subscriber_1', '#callback']
],
[['state/components/1/status', 'state/components/1/status', '#subscriber_2']]
],
[
'MUST not affect other subscriber when one topic is removed from the topic tree',
[
['subscribe', 'state/components/+/status', '#subscriber', '#callback'],
['subscribe', 'state/components/1/status', '#subscriber', '#callback'],
['unsubscribe', 'state/components/+/status', '#subscriber', '#callback']
],
[['state/components/1/status', 'state/components/1/status', '#subscriber']]
]
]
'#subscribe': [
[
'MUST publish a single matched exact topic "setup/rooms/1/name"',
[
['subscribe', 'setup/rooms/1/name', '#subscriber', '#callback', { immediate: false }],
['set', '/setup/rooms/1/name', 'Kitchen']
],
[
['setup/rooms/1/name', '/setup/rooms/1/name', 'Kitchen' ]
]
],
[
'MUST publish a single matched exact topic "setup/rooms/1/name" with immediate flag',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Patio'],
['subscribe', 'setup/rooms/1/name', '#subscriber', '#callback']
],
[
['setup/rooms/1/name', '/setup/rooms/1/name', 'Kitchen' ]
]
],
[
'MUST publish the root wildcard topic "#"',
[
['subscribe', '#', '#subscriber', '#callback', { immediate: false }],
['set', '/setup/rooms/1/name', 'Kitchen']
],
[
['#', '/setup', {}],
['#', '/setup/rooms', {}],
['#', '/setup/rooms/1', {}],
['#', '/setup/rooms/1/name', 'Kitchen']
]
],
[
'MUST publish a single matched wildcard topic containing "#", "setup/#"',
[
['write', '/setup/rooms/1/name', 'Patio'],
['subscribe', 'setup/#', '#subscriber', '#callback', { immediate: false }],
['write', '/setup/rooms/1/name', 'Kitchen']
],
[['setup/#', '/setup/rooms/1/name', 'Kitchen']]
],
[
'MUST publish a single matched wildcard topic containing "+", "setup/rooms/+/name"',
[
['subscribe', 'setup/rooms/+/name', '#subscriber', '#callback', { immediate: false }],
['set', '/setup/rooms/1/name', 'Kitchen']
],
[
['setup/rooms/+/name', '/setup/rooms/1/name', 'Kitchen' ]
]
],
[
'MUST publish a single matched wildcard topic containing "*", "setup/rooms/*"',
[
['subscribe', 'setup/rooms/*', '#subscriber', '#callback', { immediate: false }],
['set', '/setup/rooms/1/name', 'Kitchen']
],
[
['setup/rooms/*', '/setup/rooms', { '1': { } }],
['setup/rooms/*', '/setup/rooms', { '1': { 'name': 'Kitchen' } }]
]
],
[
'MUST publish a single matched wildcard topic ending with "+", "setup/rooms/1/+"',
[
['subscribe', 'setup/rooms/1/+', '#subscriber', '#callback', { immediate: false }],
['set', '/setup/rooms/1/name', 'Kitchen']
],
[
['setup/rooms/1/+', '/setup/rooms/1/name', 'Kitchen']
]
],
[
'MUST publish a wildcard topic with two "+", "setup/+/+"',
[
['subscribe', 'setup/+/+', '#subscriber', '#callback', { immediate: false }],
['write', '/setup/rooms/1/name', 'Kitchen']
],
[['setup/+/+', '/setup/rooms/1', {}]]
],
[
'MUST publish a wildcard topic with "+" and "#", "setup/+/#"',
[
['subscribe', 'setup/+/#', '#subscriber', '#callback', { immediate: false }],
['write', '/setup/rooms/1/name', 'Kitchen']
],
[
['setup/+/#', '/setup/rooms/1', {}],
['setup/+/#', '/setup/rooms/1/name', 'Kitchen']
]
],
[
'MUST publish a wildcard topic with "+" and "*", "setup/+/*"',
[
['subscribe', 'setup/+/*', '#subscriber', '#callback', { immediate: false }],
['write', '/setup/rooms/1/name', 'Kitchen']
],
[
['setup/+/*', '/setup/rooms', { '1': {} }],
['setup/+/*', '/setup/rooms', { '1': { 'name': 'Kitchen' }}]
]
],
[
'MUST publish the root wildcard topic "#" with immediate flag',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['subscribe', '#', '#subscriber', '#callback']
],
[['#', '/setup/rooms/1/name', 'Kitchen']]
],
[
'MUST publish multiple matching paths with immediate flag',
[
['set', '/setup/rooms/1/name', 'Kitchen'],
['set', '/setup/rooms/2/name', 'Patio'],
['subscribe', '#', '#subscriber', '#callback']
],
[
['#', '/setup/rooms/1/name', 'Kitchen'],
['#', '/setup/rooms/2/name', 'Patio']
]
],
[
'MUST publish multiple matched subscribers',
[
['subscribe', 'setup/rooms/+/name', '#subscriber', '#callback', { immediate: false }],
['subscribe', 'setup/rooms/1/name', '#subscriber', '#callback', { immediate: false }],
['set', '/setup/rooms/1/name', 'Patio']
],
[
['setup/rooms/1/name', '/setup/rooms/1/name', 'Patio'],
['setup/rooms/+/name', '/setup/rooms/1/name', 'Patio']
]
],
[
'FLAGGED > MUST publish a null value for a single matched wildcard topic ending in "*", "setup/*"',
[
['write', '/setup/rooms/1/name', 'Kitchen'],
['subscribe', 'setup/*', '#subscriber', '#callback', { immediate: false }],
['write', '/setup/rooms/1', null]
],
[
['setup/*', '/setup', null]
]
],
[
'FLAGGED > MUST publish a single matched topic if a parent node is deleted, "setup/rooms/1/name"',
[
['write', '/setup/rooms/1/name', 'Kitchen'],
['subscribe', 'setup/rooms/1/name', '#subscriber', '#callback', { immediate: false }],
['write', '/setup/rooms/1', null]
],
[['setup/rooms/+/name', '/setup/rooms/1/name', null]]
],
[
'FLAGGED > MUST publish a single matched wildcard topic if a parent node is deleted, "setup/rooms/1/name"',
[
['write', '/setup/rooms/1/name', 'Kitchen'],
['subscribe', 'setup/rooms/+/name', '#subscriber', '#callback', { immediate: false }],
['write', '/setup/rooms/1', null]
],
[['setup/rooms/+/name', '/setup/rooms/1/name', null]]
]
]
'#unsubscribe': [
[
'MUST NOT error if pointer has no subscribers',
[['subscribe', 'expected/to/error', '#subscriber', '#callback', { immediate: false }]],
[]
],
[
'MUST NOT error if pointer has no subscribers',
[['subscribe', 'expected/to/error', '#subscriber', '#callback', { immediate: false }]],
[]
]
]