git ssb

0+

Piet / ssb-loomio



Commit 80c90c52e4088319b7d48db43edeb53d3bba8ffe

Merge pull request #21 from ssbc/build-publish

Rename and pass tests
mix irving authored on 3/16/2018, 3:48:22 AM
GitHub committed on 3/16/2018, 3:48:22 AM
Parent: ea9a423663b274022b27c3a9574fc2dfefa5b165
Parent: 7b830c35a60fe8e303f9e2f3a156a6f3516a8cb1

Files changed

poll/async/get.jschanged
poll/async/chooseOne.jsdeleted
poll/async/publishChooseOne.jsadded
poll/sync/chooseOne.jsdeleted
poll/sync/buildChooseOne.jsadded
poll/sync/poll.jsdeleted
poll/sync/buildPoll.jsadded
position/async/chooseOne.jsdeleted
position/async/buildChooseOne.jsadded
position/async/position.jsdeleted
position/async/buildPosition.jsadded
position/sync/chooseOneResults.jsdeleted
position/sync/buildResults.jsadded
test/errors/sync/index.test.jschanged
test/poll/async/get.test.jschanged
test/poll/sync/chooseOne.test.jsdeleted
test/poll/sync/buildChooseOne.test.jsadded
test/position/async/chooseOne.test.jsdeleted
test/position/async/buildChooseOne.test.jsadded
test/position/sync/chooseOneResults.test.jsdeleted
test/position/sync/buildResults.test.jsadded
poll/async/get.jsView
@@ -3,9 +3,9 @@
33 const { isPoll, isPosition, isChooseOnePoll, isChooseOnePosition } = require('ssb-poll-schema')
44 isPoll.chooseOne = isChooseOnePoll
55 isPosition.chooseOne = isChooseOnePosition
66 const { ERROR_POSITION_TYPE } = require('../../types')
7-const getResults = require('../../position/sync/chooseOneResults')
7+const getResults = require('../../position/sync/buildResults')
88 const getMsgContent = require('../../lib/getMsgContent')
99
1010 module.exports = function (server) {
1111 return function get (key, cb) {
poll/async/chooseOne.jsView
@@ -1,13 +1,0 @@
1-const ChooseOne = require('../sync/chooseOne')
2-const { isPoll } = require('ssb-poll-schema')
3-
4-module.exports = function (server) {
5- return function publishChooseOne (opts, cb) {
6- const poll = ChooseOne(opts)
7- console.log('poll', poll)
8- console.log('isChooseOnePoll', require('../../isPoll'))
9- if (!isPoll.chooseOne(poll)) return cb(isPoll.chooseOne.errors)
10-
11- server.publish(poll, cb)
12- }
13-}
poll/async/publishChooseOne.jsView
@@ -1,0 +1,13 @@
1+const ChooseOne = require('../sync/buildChooseOne')
2+const { isPoll } = require('ssb-poll-schema')
3+
4+module.exports = function (server) {
5+ return function publishChooseOne (opts, cb) {
6+ const poll = ChooseOne(opts)
7+ console.log('poll', poll)
8+ console.log('isChooseOnePoll', require('../../isPoll'))
9+ if (!isPoll.chooseOne(poll)) return cb(isPoll.chooseOne.errors)
10+
11+ server.publish(poll, cb)
12+ }
13+}
poll/sync/chooseOne.jsView
@@ -1,19 +1,0 @@
1-const Poll = require('./poll')
2-const { CHOOSE_ONE } = require('../../types')
3-
4-function ChooseOne ({ choices, title, closesAt, body, channel, recps, mentions }) {
5- return Poll({
6- details: {
7- choices,
8- type: CHOOSE_ONE
9- },
10- title,
11- closesAt,
12- body,
13- channel,
14- recps,
15- mentions
16- })
17-}
18-
19-module.exports = ChooseOne
poll/sync/buildChooseOne.jsView
@@ -1,0 +1,19 @@
1+const Poll = require('./buildPoll')
2+const { CHOOSE_ONE } = require('../../types')
3+
4+function ChooseOne ({ choices, title, closesAt, body, channel, recps, mentions }) {
5+ return Poll({
6+ details: {
7+ choices,
8+ type: CHOOSE_ONE
9+ },
10+ title,
11+ closesAt,
12+ body,
13+ channel,
14+ recps,
15+ mentions
16+ })
17+}
18+
19+module.exports = ChooseOne
poll/sync/poll.jsView
@@ -1,41 +1,0 @@
1-// var { link } = require('ssb-msg-schemas/util')
2-const {versionStrings: {V1_SCHEMA_VERSION_STRING}} = require('ssb-poll-schema')
3-
4-function Poll ({ details, title, closesAt, body, channel, recps, mentions }) {
5- var content = { type: 'poll', details, title, closesAt, version: V1_SCHEMA_VERSION_STRING }
6-
7- if (body) content.body = body
8-
9- // if (root) {
10- // root = link(root)
11- // if (!root) { throw new Error('root is not a valid link') }
12- // content.root = root
13- // }
14- // if (branch) {
15- // if (!root) { throw new Error('root is not a valid link') }
16- // branch = Array.isArray(branch) ? branch.map(link) : link(branch)
17- // if (!branch) { throw new Error('branch is not a valid link') }
18- // content.branch = branch
19- // }
20- //
21- // // NOTE mentions can be derived from text,
22- // // or we could leave it so you can manually notify people without having to at-mention spam the text
23- // if (mentions && (!Array.isArray(mentions) || mentions.length)) {
24- // mentions = links(mentions)
25- // if (!mentions || !mentions.length) { throw new Error('mentions are not valid links') }
26- // content.mentions = mentions
27- // }
28- // if (recps && (!Array.isArray(recps) || recps.length)) {
29- // recps = links(recps)
30- // if (!recps || !recps.length) { throw new Error('recps are not valid links') }
31- // content.recps = recps
32- // }
33- if (channel) {
34- if (typeof channel !== 'string') { throw new Error('channel must be a string') }
35- content.channel = channel
36- }
37-
38- return content
39-}
40-
41-module.exports = Poll
poll/sync/buildPoll.jsView
@@ -1,0 +1,41 @@
1+// var { link } = require('ssb-msg-schemas/util')
2+const {versionStrings: {V1_SCHEMA_VERSION_STRING}} = require('ssb-poll-schema')
3+
4+function Poll ({ details, title, closesAt, body, channel, recps, mentions }) {
5+ var content = { type: 'poll', details, title, closesAt, version: V1_SCHEMA_VERSION_STRING }
6+
7+ if (body) content.body = body
8+
9+ // if (root) {
10+ // root = link(root)
11+ // if (!root) { throw new Error('root is not a valid link') }
12+ // content.root = root
13+ // }
14+ // if (branch) {
15+ // if (!root) { throw new Error('root is not a valid link') }
16+ // branch = Array.isArray(branch) ? branch.map(link) : link(branch)
17+ // if (!branch) { throw new Error('branch is not a valid link') }
18+ // content.branch = branch
19+ // }
20+ //
21+ // // NOTE mentions can be derived from text,
22+ // // or we could leave it so you can manually notify people without having to at-mention spam the text
23+ // if (mentions && (!Array.isArray(mentions) || mentions.length)) {
24+ // mentions = links(mentions)
25+ // if (!mentions || !mentions.length) { throw new Error('mentions are not valid links') }
26+ // content.mentions = mentions
27+ // }
28+ // if (recps && (!Array.isArray(recps) || recps.length)) {
29+ // recps = links(recps)
30+ // if (!recps || !recps.length) { throw new Error('recps are not valid links') }
31+ // content.recps = recps
32+ // }
33+ if (channel) {
34+ if (typeof channel !== 'string') { throw new Error('channel must be a string') }
35+ content.channel = channel
36+ }
37+
38+ return content
39+}
40+
41+module.exports = Poll
position/async/chooseOne.jsView
@@ -1,18 +1,0 @@
1-const createPosition = require('./position')
2-const { CHOOSE_ONE } = require('../../types')
3-
4-module.exports = function (server) {
5- const Position = createPosition(server)
6- return function ChooseOne ({ poll, choice, reason, channel, mentions }, cb) {
7- Position({
8- poll,
9- details: {
10- type: CHOOSE_ONE,
11- choice
12- },
13- reason,
14- channel,
15- mentions
16- }, cb)
17- }
18-}
position/async/buildChooseOne.jsView
@@ -1,0 +1,18 @@
1+const createPosition = require('./buildPosition')
2+const { CHOOSE_ONE } = require('../../types')
3+
4+module.exports = function (server) {
5+ const Position = createPosition(server)
6+ return function ChooseOne ({ poll, choice, reason, channel, mentions }, cb) {
7+ Position({
8+ poll,
9+ details: {
10+ type: CHOOSE_ONE,
11+ choice
12+ },
13+ reason,
14+ channel,
15+ mentions
16+ }, cb)
17+ }
18+}
position/async/position.jsView
@@ -1,50 +1,0 @@
1-const sort = require('ssb-sort')
2-
3-const GetPoll = require('../../poll/async/get')
4-const {versionStrings: {V1_SCHEMA_VERSION_STRING}} = require('ssb-poll-schema')
5-// var { link } = require('ssb-msg-schemas/util')
6-//
7-
8-module.exports = function (server) {
9- const getPoll = GetPoll(server)
10-
11- return function Position ({ poll = {}, details, reason, channel, mentions }, cb) {
12- const content = {
13- type: 'position',
14- version: V1_SCHEMA_VERSION_STRING,
15- root: typeof poll === 'string' ? poll : poll.key,
16- details
17- }
18-
19- if (reason) content.reason = reason
20-
21- if (channel) {
22- if (typeof channel !== 'string') { throw new Error('channel must be a string') }
23- content.channel = channel
24- }
25-
26- if (content.root && server) {
27- getPoll(content.root, (err, {positions}) => {
28- content.branch = sort.heads(positions)
29- cb(err, content)
30- })
31- } else {
32- cb(null, content)
33- }
34-
35- // // NOTE mentions can be derived from text,
36- // // or we could leave it so you can manually notify people without having to at-mention spam the text
37- // if (mentions && (!Array.isArray(mentions) || mentions.length)) {
38- // mentions = links(mentions)
39- // if (!mentions || !mentions.length) { throw new Error('mentions are not valid links') }
40- // content.mentions = mentions
41- // }
42-
43- // // NOTE recps should be derived from the poll I think
44- // if (recps && (!Array.isArray(recps) || recps.length)) {
45- // recps = links(recps)
46- // if (!recps || !recps.length) { throw new Error('recps are not valid links') }
47- // content.recps = recps
48- // }
49- }
50-}
position/async/buildPosition.jsView
@@ -1,0 +1,50 @@
1+const sort = require('ssb-sort')
2+
3+const GetPoll = require('../../poll/async/get')
4+const {versionStrings: {V1_SCHEMA_VERSION_STRING}} = require('ssb-poll-schema')
5+// var { link } = require('ssb-msg-schemas/util')
6+//
7+
8+module.exports = function (server) {
9+ const getPoll = GetPoll(server)
10+
11+ return function Position ({ poll = {}, details, reason, channel, mentions }, cb) {
12+ const content = {
13+ type: 'position',
14+ version: V1_SCHEMA_VERSION_STRING,
15+ root: typeof poll === 'string' ? poll : poll.key,
16+ details
17+ }
18+
19+ if (reason) content.reason = reason
20+
21+ if (channel) {
22+ if (typeof channel !== 'string') { throw new Error('channel must be a string') }
23+ content.channel = channel
24+ }
25+
26+ if (content.root && server) {
27+ getPoll(content.root, (err, {positions}) => {
28+ content.branch = sort.heads(positions)
29+ cb(err, content)
30+ })
31+ } else {
32+ cb(null, content)
33+ }
34+
35+ // // NOTE mentions can be derived from text,
36+ // // or we could leave it so you can manually notify people without having to at-mention spam the text
37+ // if (mentions && (!Array.isArray(mentions) || mentions.length)) {
38+ // mentions = links(mentions)
39+ // if (!mentions || !mentions.length) { throw new Error('mentions are not valid links') }
40+ // content.mentions = mentions
41+ // }
42+
43+ // // NOTE recps should be derived from the poll I think
44+ // if (recps && (!Array.isArray(recps) || recps.length)) {
45+ // recps = links(recps)
46+ // if (!recps || !recps.length) { throw new Error('recps are not valid links') }
47+ // content.recps = recps
48+ // }
49+ }
50+}
position/sync/chooseOneResults.jsView
@@ -1,66 +1,0 @@
1-const getMsgContent = require('../../lib/getMsgContent')
2-const ChooseOne = require('../../poll/sync/chooseOne')
3-const PositionChoiceError = require('../../errors/sync/positionChoiceError')
4-const PositionLateError = require('../../errors/sync/positionLateError')
5-
6-// Expects `poll` and `position` objects passed in to be of shape:
7-// {
8-// key,
9-// value: {
10-// content: {...},
11-// timestamp: ...
12-// author: ...
13-// }
14-// }
15-//
16-// postions must be of the correct type ie: type checked by the caller.
17-module.exports = function chooseOneResults ({positions, poll}) {
18- var results = getMsgContent(poll)
19- .details
20- .choices
21- .map(choice => {
22- return {
23- choice,
24- voters: {}
25- }
26- })
27-
28- return positions.reduce(function (acc, position) {
29- const { author, content } = position.value
30- const { choice } = content.details
31-
32- if (isInvalidChoice({position, poll})) {
33- acc.errors.push(PositionChoiceError({position}))
34- return acc
35- }
36-
37- if (isPositionLate({position, poll})) {
38- acc.errors.push(PositionLateError({position}))
39- return acc
40- }
41-
42- deleteExistingVotesByAuthor({results: acc.results, author})
43- acc.results[choice].voters[author] = position
44-
45- return acc
46- }, {errors: [], results})
47-}
48-
49-// !!! assumes these are already sorted by time.
50-// modifies results passed in
51-function deleteExistingVotesByAuthor ({author, results}) {
52- results.forEach(result => {
53- if (result.voters[author]) {
54- delete result.voters[author]
55- }
56- })
57-}
58-
59-function isInvalidChoice ({position, poll}) {
60- const { choice } = position.value.content.details
61- return choice >= poll.value.content.details.choices.length
62-}
63-
64-function isPositionLate ({position, poll}) {
65- return position.value.timestamp > poll.value.content.closesAt
66-}
position/sync/buildResults.jsView
@@ -1,0 +1,72 @@
1+const getMsgContent = require('../../lib/getMsgContent')
2+const PositionChoiceError = require('../../errors/sync/positionChoiceError')
3+const PositionLateError = require('../../errors/sync/positionLateError')
4+const { isChooseOnePoll } = require('ssb-poll-schema')
5+
6+// Expects `poll` and `position` objects passed in to be of shape:
7+// {
8+// key,
9+// value: {
10+// content: {...},
11+// timestamp: ...
12+// author: ...
13+// }
14+// }
15+//
16+// postions must be of the correct type ie: type checked by the caller.
17+module.exports = function ({positions, poll}) {
18+ if (isChooseOnePoll(poll)) {
19+ return chooseOneResults({positions, poll})
20+ }
21+}
22+
23+function chooseOneResults ({positions, poll}) {
24+ var results = getMsgContent(poll)
25+ .details
26+ .choices
27+ .map(choice => {
28+ return {
29+ choice,
30+ voters: {}
31+ }
32+ })
33+
34+ return positions.reduce(function (acc, position) {
35+ const { author, content } = position.value
36+ const { choice } = content.details
37+
38+ if (isInvalidChoice({position, poll})) {
39+ acc.errors.push(PositionChoiceError({position}))
40+ return acc
41+ }
42+
43+ if (isPositionLate({position, poll})) {
44+ acc.errors.push(PositionLateError({position}))
45+ return acc
46+ }
47+
48+ deleteExistingVotesByAuthor({results: acc.results, author})
49+ acc.results[choice].voters[author] = position
50+
51+ return acc
52+ }, {errors: [], results})
53+}
54+
55+// !!! assumes these are already sorted by time.
56+// modifies results passed in
57+function deleteExistingVotesByAuthor ({author, results}) {
58+ results.forEach(result => {
59+ if (result.voters[author]) {
60+ delete result.voters[author]
61+ }
62+ })
63+}
64+
65+function isInvalidChoice ({position, poll}) {
66+ const { choice } = position.value.content.details
67+ return choice >= poll.value.content.details.choices.length
68+}
69+
70+function isPositionLate ({position, poll}) {
71+ return position.value.timestamp > poll.value.content.closesAt
72+}
test/errors/sync/index.test.jsView
@@ -9,9 +9,9 @@
99 const PositionTypeError = require('../../../errors/sync/positionTypeError')
1010 const PositionLateError = require('../../../errors/sync/positionLateError')
1111 const PositionChoiceError = require('../../../errors/sync/positionChoiceError')
1212
13-const ChooseOne = require('../../../position/async/chooseOne')()
13+const ChooseOne = require('../../../position/async/buildChooseOne')()
1414
1515 test('positionTypeError', function (t) {
1616 pull(
1717 pullAsync(cb => {
test/poll/async/get.test.jsView
@@ -1,17 +1,17 @@
11 var test = require('tape')
22 var Server = require('scuttle-testbot')
33 var pull = require('pull-stream')
44
5-var ChooseOnePoll = require('../../../poll/sync/chooseOne')
5+var ChooseOnePoll = require('../../../poll/sync/buildChooseOne')
66 var getPoll = require('../../../poll/async/get')
77
88 Server
99 .use(require('ssb-backlinks'))
1010
1111 var server = Server({name: 'testBotName'})
1212
13-var ChooseOne = require('../../../position/async/chooseOne')(server)
13+var ChooseOne = require('../../../position/async/buildChooseOne')(server)
1414
1515 var katie = server.createFeed()
1616 var piet = server.createFeed()
1717
test/poll/sync/chooseOne.test.jsView
@@ -1,29 +1,0 @@
1-const test = require('tape')
2-const ChooseOne = require('../../../poll/sync/chooseOne')
3-const {isPoll, isChooseOnePoll} = require('ssb-poll-schema')
4-
5-test('Position - ChooseOne', function (t) {
6- var invalidPoll = ChooseOne({
7- })
8- t.false(isPoll(invalidPoll), 'invalid')
9-
10- var validPoll = ChooseOne({
11- title: 'how many food',
12- choices: [1, 2, 'three'],
13- closesAt: new Date().toISOString()
14- })
15- t.true(isPoll(validPoll), 'simple (passes isPoll)')
16- t.true(isChooseOnePoll(validPoll), 'simple (passes isChooseOnePoll)')
17-
18- var fullPollMsg = {
19- key: '%somekey',
20- value: {
21- content: validPoll
22- }
23- }
24- t.true(isPoll(fullPollMsg), 'simple (full msg)')
25- // NOTE - we might want an isChooseOnePoll in future
26- // t.true(isChooseOnePoll(fullPollMsg), 'simple (full msg)')
27-
28- t.end()
29-})
test/poll/sync/buildChooseOne.test.jsView
@@ -1,0 +1,29 @@
1+const test = require('tape')
2+const ChooseOne = require('../../../poll/sync/buildChooseOne')
3+const {isPoll, isChooseOnePoll} = require('ssb-poll-schema')
4+
5+test('Position - ChooseOne', function (t) {
6+ var invalidPoll = ChooseOne({
7+ })
8+ t.false(isPoll(invalidPoll), 'invalid')
9+
10+ var validPoll = ChooseOne({
11+ title: 'how many food',
12+ choices: [1, 2, 'three'],
13+ closesAt: new Date().toISOString()
14+ })
15+ t.true(isPoll(validPoll), 'simple (passes isPoll)')
16+ t.true(isChooseOnePoll(validPoll), 'simple (passes isChooseOnePoll)')
17+
18+ var fullPollMsg = {
19+ key: '%somekey',
20+ value: {
21+ content: validPoll
22+ }
23+ }
24+ t.true(isPoll(fullPollMsg), 'simple (full msg)')
25+ // NOTE - we might want an isChooseOnePoll in future
26+ // t.true(isChooseOnePoll(fullPollMsg), 'simple (full msg)')
27+
28+ t.end()
29+})
test/position/async/chooseOne.test.jsView
@@ -1,77 +1,0 @@
1-const test = require('tape')
2-const pull = require('pull-stream')
3-const pullAsync = require('pull-async')
4-const ChooseOne = require('../../../position/async/chooseOne')()
5-const {isPosition} = require('ssb-poll-schema')
6-
7-test('Position - ChooseOne', function (t) {
8- pull(
9- pullAsync(cb => {
10- ChooseOne({
11- poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256'
12- }, cb)
13- }),
14- pull.drain((missingChoice) => {
15- t.false(isPosition(missingChoice), 'missing a choice')
16- })
17- )
18-
19- pull(
20- pullAsync(cb => {
21- ChooseOne({
22- choice: 0
23- }, cb)
24- }),
25- pull.drain((missingPoll) => {
26- t.false(isPosition(missingPoll), 'missing a poll')
27- })
28- )
29-
30- pull(
31- pullAsync(cb => {
32- ChooseOne({
33- poll: 'dog?',
34- choice: 0
35- }, cb)
36- }),
37- pull.drain((missingPoll) => {
38- t.false(isPosition(missingPoll), 'does not reference a poll')
39- })
40- )
41-
42- pull(
43- pullAsync(cb => {
44- ChooseOne({
45- poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256',
46- choice: 0
47- }, cb)
48- }),
49- pull.drain((poll) => {
50- t.true(isPosition(poll), 'simple')
51- })
52- )
53-
54- pull(
55- pullAsync(cb => {
56- ChooseOne({
57- poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256',
58- choice: 0
59- }, cb)
60- }),
61- pull.map((validPosition) => {
62- return {
63- key: '%somekey',
64- value: {
65- content: validPosition
66- }
67- }
68- }),
69- pull.drain((poll) => {
70- t.true(isPosition(poll), 'simple (full msg)')
71- t.end()
72- })
73- )
74-
75- // NOTE - we might want an isChooseOnePosition in future
76- // t.true(isChooseOnePosition(fullPositionMsg), 'simple (full msg)')
77-})
test/position/async/buildChooseOne.test.jsView
@@ -1,0 +1,77 @@
1+const test = require('tape')
2+const pull = require('pull-stream')
3+const pullAsync = require('pull-async')
4+const ChooseOne = require('../../../position/async/buildChooseOne')()
5+const {isPosition} = require('ssb-poll-schema')
6+
7+test('Position - ChooseOne', function (t) {
8+ pull(
9+ pullAsync(cb => {
10+ ChooseOne({
11+ poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256'
12+ }, cb)
13+ }),
14+ pull.drain((missingChoice) => {
15+ t.false(isPosition(missingChoice), 'missing a choice')
16+ })
17+ )
18+
19+ pull(
20+ pullAsync(cb => {
21+ ChooseOne({
22+ choice: 0
23+ }, cb)
24+ }),
25+ pull.drain((missingPoll) => {
26+ t.false(isPosition(missingPoll), 'missing a poll')
27+ })
28+ )
29+
30+ pull(
31+ pullAsync(cb => {
32+ ChooseOne({
33+ poll: 'dog?',
34+ choice: 0
35+ }, cb)
36+ }),
37+ pull.drain((missingPoll) => {
38+ t.false(isPosition(missingPoll), 'does not reference a poll')
39+ })
40+ )
41+
42+ pull(
43+ pullAsync(cb => {
44+ ChooseOne({
45+ poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256',
46+ choice: 0
47+ }, cb)
48+ }),
49+ pull.drain((poll) => {
50+ t.true(isPosition(poll), 'simple')
51+ })
52+ )
53+
54+ pull(
55+ pullAsync(cb => {
56+ ChooseOne({
57+ poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256',
58+ choice: 0
59+ }, cb)
60+ }),
61+ pull.map((validPosition) => {
62+ return {
63+ key: '%somekey',
64+ value: {
65+ content: validPosition
66+ }
67+ }
68+ }),
69+ pull.drain((poll) => {
70+ t.true(isPosition(poll), 'simple (full msg)')
71+ t.end()
72+ })
73+ )
74+
75+ // NOTE - we might want an isChooseOnePosition in future
76+ // t.true(isChooseOnePosition(fullPositionMsg), 'simple (full msg)')
77+})
test/position/sync/chooseOneResults.test.jsView
@@ -1,209 +1,0 @@
1-const test = require('tape')
2-const pull = require('pull-stream')
3-const ChooseOne = require('../../../position/async/chooseOne')()
4-const ChooseOnePoll = require('../../../poll/sync/chooseOne')
5-const chooseOneResults = require('../../../position/sync/chooseOneResults')
6-const {ERROR_POSITION_CHOICE, ERROR_POSITION_LATE} = require('../../../types')
7-
8-const pietId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/0=.ed25519'
9-const mixId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/1=.ed25519'
10-const mikeyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/2=.ed25519'
11-const timmyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/3=.ed25519'
12-const tommyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/4=.ed25519'
13-const sallyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/5=.ed25519'
14-
15-const poll = '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256'
16-
17-const now = Number(new Date())
18-
19-const validPoll = {
20- key: '%schwoop',
21- value: {
22- content: ChooseOnePoll({
23- choices: [1, 2, 'three'],
24- title: 'how many food',
25- closesAt: now
26- })
27- }
28-}
29-
30-test('ChooseOneResults - ChooseOneResults', function (t) {
31- const positions = [
32- { value: { content: {choice: 0, poll}, author: pietId } },
33- { value: { content: {choice: 0, poll}, author: mixId } },
34- { value: { content: {choice: 0, poll}, author: mikeyId } },
35- { value: { content: {choice: 1, poll}, author: timmyId } },
36- { value: { content: {choice: 1, poll}, author: tommyId } },
37- { value: { content: {choice: 2, poll}, author: sallyId } }
38- ]
39-
40- const expected = {
41- results: [
42- {
43- choice: 1,
44- voters: {
45- [pietId]: positions[0],
46- [mixId]: positions[1],
47- [mikeyId]: positions[2]
48- }
49- },
50- {
51- choice: 2,
52- voters: {
53- [timmyId]: positions[3],
54- [tommyId]: positions[4]
55- }
56- },
57- {
58- choice: 'three',
59- voters: {
60- [sallyId]: positions[5]
61- }
62- }
63- ],
64- errors: {}
65- }
66-
67- pull(
68- pull.values(positions),
69- pull.asyncMap((fullPosition, cb) => {
70- ChooseOne(fullPosition.value.content, (err, position) => {
71- fullPosition.value.content = position
72- cb(err, fullPosition)
73- })
74- }),
75- pull.collect(postions => {
76- const actual = chooseOneResults({positions, poll: validPoll})
77- t.deepEqual(actual, expected, 'results are correct')
78- t.end()
79- })
80- )
81-})
82-
83-test('ChooseOneResults - a position stated for an invalid choice index is not counted', function (t) {
84- const positions = [
85- { value: { content: {choice: 3, poll}, author: pietId } }
86- ]
87-
88- pull(
89- pull.values(positions),
90- pull.asyncMap((fullPosition, cb) => {
91- ChooseOne(fullPosition.value.content, (err, position) => {
92- fullPosition.value.content = position
93- cb(err, fullPosition)
94- })
95- }),
96- pull.collect(postions => {
97- const actual = chooseOneResults({positions, poll: validPoll})
98- t.false(actual.results[3], 'invalid vote is not counted')
99- t.end()
100- })
101- )
102-})
103-
104-test('ChooseOneResults - a position stated for an invalid choice index is included in the errors object', function (t) {
105- const positions = [
106- { value: { content: {choice: 3, poll}, author: pietId } }
107- ]
108-
109- pull(
110- pull.values(positions),
111- pull.asyncMap((fullPosition, cb) => {
112- ChooseOne(fullPosition.value.content, (err, position) => {
113- fullPosition.value.content = position
114- cb(err, fullPosition)
115- })
116- }),
117- pull.collect(postions => {
118- const actual = chooseOneResults({positions, poll: validPoll})
119- t.deepEqual(actual.errors[0].type, ERROR_POSITION_CHOICE, 'invalid vote is on error object')
120- t.end()
121- })
122- )
123-})
124-
125-test('ChooseOneResults - A position stated before the closing time of the poll is counted', function (t) {
126- const positions = [
127- { value: { content: {choice: 0, poll}, author: pietId, timestamp: now - 1 } }
128- ]
129-
130- pull(
131- pull.values(positions),
132- pull.asyncMap((fullPosition, cb) => {
133- ChooseOne(fullPosition.value.content, (err, position) => {
134- fullPosition.value.content = position
135- cb(err, fullPosition)
136- })
137- }),
138- pull.collect(postions => {
139- const actual = chooseOneResults({positions, poll: validPoll})
140- t.ok(actual.results[0].voters[pietId], 'valid vote is counted')
141- t.end()
142- })
143- )
144-})
145-
146-test('ChooseOneResults - A position stated after the closing time of the poll is not counted', function (t) {
147- const positions = [
148- { value: { content: {choice: 0, poll}, author: pietId, timestamp: now + 1 } }
149- ]
150-
151- pull(
152- pull.values(positions),
153- pull.asyncMap((fullPosition, cb) => {
154- ChooseOne(fullPosition.value.content, (err, position) => {
155- fullPosition.value.content = position
156- cb(err, fullPosition)
157- })
158- }),
159- pull.collect(postions => {
160- const actual = chooseOneResults({positions, poll: validPoll})
161- t.deepEqual(actual.results[0].voters, {}, 'invalid vote is not counted')
162- t.end()
163- })
164- )
165-})
166-
167-test('ChooseOneResults - A position stated after the closing time of the poll is included in the error object', function (t) {
168- const positions = [
169- { value: { content: {choice: 0, poll}, author: pietId, timestamp: now + 1 } }
170- ]
171-
172- pull(
173- pull.values(positions),
174- pull.asyncMap((fullPosition, cb) => {
175- ChooseOne(fullPosition.value.content, (err, position) => {
176- fullPosition.value.content = position
177- cb(err, fullPosition)
178- })
179- }),
180- pull.collect(postions => {
181- const actual = chooseOneResults({positions, poll: validPoll})
182- t.deepEqual(actual.errors[0].type, ERROR_POSITION_LATE, 'invalid vote is on error object')
183- t.end()
184- })
185- )
186-})
187-
188-test('ChooseOneResults - ChooseOneResults only counts latest vote by an author', function (t) {
189- const positions = [
190- { value: { content: {choice: 2, poll}, author: pietId } },
191- { value: { content: {choice: 0, poll}, author: pietId } }
192- ]
193-
194- pull(
195- pull.values(positions),
196- pull.asyncMap((fullPosition, cb) => {
197- ChooseOne(fullPosition.value.content, (err, position) => {
198- fullPosition.value.content = position
199- cb(err, fullPosition)
200- })
201- }),
202- pull.collect(postions => {
203- const actual = chooseOneResults({positions, poll: validPoll})
204- t.false(actual.results[2].voters[pietId], 'old vote is deleted')
205- t.true(actual.results[0].voters[pietId], 'new vote is counted')
206- t.end()
207- })
208- )
209-})
test/position/sync/buildResults.test.jsView
@@ -1,0 +1,210 @@
1+const test = require('tape')
2+const pull = require('pull-stream')
3+const ChooseOne = require('../../../position/async/buildChooseOne')()
4+const ChooseOnePoll = require('../../../poll/sync/buildChooseOne')
5+const chooseOneResults = require('../../../position/sync/buildResults')
6+const {isPosition, isPoll} = require('ssb-poll-schema')
7+const {ERROR_POSITION_CHOICE, ERROR_POSITION_LATE} = require('../../../types')
8+
9+const pietId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/0=.ed25519'
10+const mixId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/1=.ed25519'
11+const mikeyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/2=.ed25519'
12+const timmyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/3=.ed25519'
13+const tommyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/4=.ed25519'
14+const sallyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/5=.ed25519'
15+
16+const poll = '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256'
17+
18+const now = new Date().toISOString()
19+
20+const validPoll = {
21+ key: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256',
22+ value: {
23+ content: ChooseOnePoll({
24+ choices: [1, 2, 'three'],
25+ title: 'how many food',
26+ closesAt: now
27+ })
28+ }
29+}
30+
31+test('ChooseOneResults - ChooseOneResults', function (t) {
32+ const positions = [
33+ { value: { content: {choice: 0, poll}, author: pietId } },
34+ { value: { content: {choice: 0, poll}, author: mixId } },
35+ { value: { content: {choice: 0, poll}, author: mikeyId } },
36+ { value: { content: {choice: 1, poll}, author: timmyId } },
37+ { value: { content: {choice: 1, poll}, author: tommyId } },
38+ { value: { content: {choice: 2, poll}, author: sallyId } }
39+ ]
40+
41+ const expected = {
42+ results: [
43+ {
44+ choice: 1,
45+ voters: {
46+ [pietId]: positions[0],
47+ [mixId]: positions[1],
48+ [mikeyId]: positions[2]
49+ }
50+ },
51+ {
52+ choice: 2,
53+ voters: {
54+ [timmyId]: positions[3],
55+ [tommyId]: positions[4]
56+ }
57+ },
58+ {
59+ choice: 'three',
60+ voters: {
61+ [sallyId]: positions[5]
62+ }
63+ }
64+ ],
65+ errors: {}
66+ }
67+
68+ pull(
69+ pull.values(positions),
70+ pull.asyncMap((fullPosition, cb) => {
71+ ChooseOne(fullPosition.value.content, (err, position) => {
72+ fullPosition.value.content = position
73+ cb(err, fullPosition)
74+ })
75+ }),
76+ pull.collect(postions => {
77+ const actual = chooseOneResults({positions, poll: validPoll})
78+ t.deepEqual(actual, expected, 'results are correct')
79+ t.end()
80+ })
81+ )
82+})
83+
84+test('ChooseOneResults - a position stated for an invalid choice index is not counted', function (t) {
85+ const positions = [
86+ { value: { content: {choice: 3, poll}, author: pietId } }
87+ ]
88+
89+ pull(
90+ pull.values(positions),
91+ pull.asyncMap((fullPosition, cb) => {
92+ ChooseOne(fullPosition.value.content, (err, position) => {
93+ fullPosition.value.content = position
94+ cb(err, fullPosition)
95+ })
96+ }),
97+ pull.collect(postions => {
98+ const actual = chooseOneResults({positions, poll: validPoll})
99+ t.false(actual.results[3], 'invalid vote is not counted')
100+ t.end()
101+ })
102+ )
103+})
104+
105+test('ChooseOneResults - a position stated for an invalid choice index is included in the errors object', function (t) {
106+ const positions = [
107+ { value: { content: {choice: 3, poll}, author: pietId } }
108+ ]
109+
110+ pull(
111+ pull.values(positions),
112+ pull.asyncMap((fullPosition, cb) => {
113+ ChooseOne(fullPosition.value.content, (err, position) => {
114+ fullPosition.value.content = position
115+ cb(err, fullPosition)
116+ })
117+ }),
118+ pull.collect(postions => {
119+ const actual = chooseOneResults({positions, poll: validPoll})
120+ t.deepEqual(actual.errors[0].type, ERROR_POSITION_CHOICE, 'invalid vote is on error object')
121+ t.end()
122+ })
123+ )
124+})
125+
126+test('ChooseOneResults - A position stated before the closing time of the poll is counted', function (t) {
127+ const positions = [
128+ { value: { content: {choice: 0, poll}, author: pietId, timestamp: now - 1 } }
129+ ]
130+
131+ pull(
132+ pull.values(positions),
133+ pull.asyncMap((fullPosition, cb) => {
134+ ChooseOne(fullPosition.value.content, (err, position) => {
135+ fullPosition.value.content = position
136+ cb(err, fullPosition)
137+ })
138+ }),
139+ pull.collect(postions => {
140+ const actual = chooseOneResults({positions, poll: validPoll})
141+ t.ok(actual.results[0].voters[pietId], 'valid vote is counted')
142+ t.end()
143+ })
144+ )
145+})
146+
147+test('ChooseOneResults - A position stated after the closing time of the poll is not counted', function (t) {
148+ const positions = [
149+ { value: { content: {choice: 0, poll}, author: pietId, timestamp: now + 1 } }
150+ ]
151+
152+ pull(
153+ pull.values(positions),
154+ pull.asyncMap((fullPosition, cb) => {
155+ ChooseOne(fullPosition.value.content, (err, position) => {
156+ fullPosition.value.content = position
157+ cb(err, fullPosition)
158+ })
159+ }),
160+ pull.collect(postions => {
161+ const actual = chooseOneResults({positions, poll: validPoll})
162+ t.deepEqual(actual.results[0].voters, {}, 'invalid vote is not counted')
163+ t.end()
164+ })
165+ )
166+})
167+
168+test('ChooseOneResults - A position stated after the closing time of the poll is included in the error object', function (t) {
169+ const positions = [
170+ { value: { content: {choice: 0, poll}, author: pietId, timestamp: now + 1 } }
171+ ]
172+
173+ pull(
174+ pull.values(positions),
175+ pull.asyncMap((fullPosition, cb) => {
176+ ChooseOne(fullPosition.value.content, (err, position) => {
177+ fullPosition.value.content = position
178+ cb(err, fullPosition)
179+ })
180+ }),
181+ pull.collect(postions => {
182+ const actual = chooseOneResults({positions, poll: validPoll})
183+ t.deepEqual(actual.errors[0].type, ERROR_POSITION_LATE, 'invalid vote is on error object')
184+ t.end()
185+ })
186+ )
187+})
188+
189+test('ChooseOneResults - ChooseOneResults only counts latest vote by an author', function (t) {
190+ const positions = [
191+ { value: { content: {choice: 2, poll}, author: pietId } },
192+ { value: { content: {choice: 0, poll}, author: pietId } }
193+ ]
194+
195+ pull(
196+ pull.values(positions),
197+ pull.asyncMap((fullPosition, cb) => {
198+ ChooseOne(fullPosition.value.content, (err, position) => {
199+ fullPosition.value.content = position
200+ cb(err, fullPosition)
201+ })
202+ }),
203+ pull.collect(postions => {
204+ const actual = chooseOneResults({positions, poll: validPoll})
205+ t.false(actual.results[2].voters[pietId], 'old vote is deleted')
206+ t.true(actual.results[0].voters[pietId], 'new vote is counted')
207+ t.end()
208+ })
209+ )
210+})

Built with git-ssb-web