From 19e880183e6c39a301a03d6c324d0bc3783746b4 Mon Sep 17 00:00:00 2001
From: Julia Friesel <julia.friesel@gmail.com>
Date: Wed, 11 Jul 2018 14:14:42 +0200
Subject: [PATCH] Accept previousCycles as array

---
 lib/sympto/index.js         | 17 +++++++++-----
 lib/sympto/pre-ovulatory.js | 23 ++++++++++++------
 test/sympto/index.spec.js   | 47 ++++++++++++++++++++++---------------
 3 files changed, 55 insertions(+), 32 deletions(-)

diff --git a/lib/sympto/index.js b/lib/sympto/index.js
index 6a9f66a3..36f8e5e6 100644
--- a/lib/sympto/index.js
+++ b/lib/sympto/index.js
@@ -4,18 +4,20 @@ import getPreOvulatoryPhase from './pre-ovulatory'
 import { LocalDate } from 'js-joda'
 import assert from 'assert'
 
-export default function ({ cycle, previousCycle }) {
-  throwIfArgsAreNotInRequiredFormat(cycle, previousCycle)
+export default function ({ cycle, previousCycles = [] }) {
+  throwIfArgsAreNotInRequiredFormat(cycle, previousCycles)
 
   const status = {
     assumeFertility: true,
     phases: {}
   }
+  // TODO handle no previous cycles
 
   // if there was no first higher measurement in the previous cycle,
   // no infertile pre-ovulatory phase may be assumed
-  if (getTemperatureShift(previousCycle).detected && !cycle[0].mucus) {
-    status.phases.preOvulatory = getPreOvulatoryPhase(cycle)
+  const lastCycle = previousCycles[previousCycles.length - 1]
+  if (getTemperatureShift(lastCycle).detected && !cycle[0].mucus) {
+    status.phases.preOvulatory = getPreOvulatoryPhase(cycle, previousCycles)
     if (status.phases.preOvulatory.cycleDays.length === cycle.length) {
       status.assumeFertility = false
       return status
@@ -70,9 +72,10 @@ export default function ({ cycle, previousCycle }) {
   return status
 }
 
-function throwIfArgsAreNotInRequiredFormat(cycle, previousCycle) {
-  [cycle, previousCycle].forEach(cycle => {
+function throwIfArgsAreNotInRequiredFormat(cycle, previousCycles) {
+  [cycle, ...previousCycles].forEach(cycle => {
     assert.ok(Array.isArray(cycle))
+    // TODO handle case of no previous cycles
     assert.ok(cycle.length > 0)
     assert.equal(typeof cycle[0].bleeding, 'object')
     assert.equal(typeof cycle[0].bleeding.value, 'number')
@@ -81,6 +84,8 @@ function throwIfArgsAreNotInRequiredFormat(cycle, previousCycle) {
       assert.doesNotThrow(() => LocalDate.parse(day.date))
       if (day.temperature) assert.equal(typeof day.temperature.value, 'number')
       if (day.mucus) assert.equal(typeof day.mucus.value, 'number')
+      if (day.mucus) assert.ok(day.mucus.value >= 0)
+      if (day.mucus) assert.ok(day.mucus.value < 5)
     })
   })
 }
\ No newline at end of file
diff --git a/lib/sympto/pre-ovulatory.js b/lib/sympto/pre-ovulatory.js
index 8cc86b9d..5749e1a2 100644
--- a/lib/sympto/pre-ovulatory.js
+++ b/lib/sympto/pre-ovulatory.js
@@ -1,13 +1,20 @@
 import { LocalDate } from "js-joda"
 
-export default function(cycle) {
+export default function(cycle, previousCycles) {
+  // TODO handle no previous cycles
+  let preOvuPhaseLength = 5
+
+  //TODO make sure it handles weird cases like fhm < 9
+  const minus8DayRuleResult = apply8DayRule(previousCycles)
+  if (minus8DayRuleResult) preOvuPhaseLength = minus8DayRuleResult
+
   const startDate = LocalDate.parse(cycle[0].date)
-  const fiveDayEndDate = startDate.plusDays(4).toString()
-  const fiveDayRuleDays = cycle.slice(0, 5).filter(d => d.date <= fiveDayEndDate)
-  const preOvulatoryDays = getDaysUntilFertileMucus(fiveDayRuleDays)
+  const preOvuPhaseEndDate = startDate.plusDays(preOvuPhaseLength - 1).toString()
+  const maybePreOvuDays = cycle.slice(0, 5).filter(d => d.date <= preOvuPhaseEndDate)
+  const preOvulatoryDays = getDaysUntilFertileMucus(maybePreOvuDays)
   let endDate
-  if (preOvulatoryDays.length === fiveDayRuleDays.length) {
-    endDate = fiveDayEndDate
+  if (preOvulatoryDays.length === maybePreOvuDays.length) {
+    endDate = preOvuPhaseEndDate
   } else {
     endDate = preOvulatoryDays[preOvulatoryDays.length - 1].date
   }
@@ -29,4 +36,6 @@ function getDaysUntilFertileMucus(days) {
     return days.slice(0, firstFertileMucusDayIndex)
   }
   return days
-}
\ No newline at end of file
+}
+
+function apply8DayRule() {}
\ No newline at end of file
diff --git a/test/sympto/index.spec.js b/test/sympto/index.spec.js
index ebc0106f..eaf1e5c6 100644
--- a/test/sympto/index.spec.js
+++ b/test/sympto/index.spec.js
@@ -23,7 +23,7 @@ describe('sympto', () => {
     it('with no shifts detects only peri-ovulatory', function () {
       const status = getSensiplanStatus({
         cycle: cycleWithoutAnyShifts,
-        previousCycle: cycleWithoutTempShift
+        previousCycles: [cycleWithoutTempShift]
       })
 
       expect(status).to.eql({
@@ -40,7 +40,7 @@ describe('sympto', () => {
     it('with shifts detects only peri-ovulatory and post-ovulatory', function () {
       const status = getSensiplanStatus({
         cycle: cycleWithTempAndMucusShift,
-        previousCycle: cycleWithoutTempShift
+        previousCycles: [cycleWithoutTempShift]
       })
 
       expect(status.temperatureShift).to.be.an('object')
@@ -66,7 +66,7 @@ describe('sympto', () => {
       it('according to 5-day-rule', function () {
         const status = getSensiplanStatus({
           cycle: fiveDayCycle,
-          previousCycle: cycleWithTempShift
+          previousCycles: [cycleWithTempShift]
         })
 
         expect(Object.keys(status.phases).length).to.eql(1)
@@ -83,7 +83,7 @@ describe('sympto', () => {
       it('according to 5-day-rule', function () {
         const status = getSensiplanStatus({
           cycle: cycleWithTempAndNoMucusShift,
-          previousCycle: cycleWithTempShift
+          previousCycles: [cycleWithTempShift]
         })
 
         expect(Object.keys(status.phases).length).to.eql(2)
@@ -101,7 +101,7 @@ describe('sympto', () => {
       it('according to 5-day-rule with shortened pre-phase', function () {
         const status = getSensiplanStatus({
           cycle: cycleWithEarlyMucus,
-          previousCycle: cycleWithTempShift
+          previousCycles: [cycleWithTempShift]
         })
 
         expect(Object.keys(status.phases).length).to.eql(2)
@@ -121,7 +121,7 @@ describe('sympto', () => {
       it('according to 5-day-rule', function () {
         const status = getSensiplanStatus({
           cycle: cycleWithTempAndMucusShift,
-          previousCycle: cycleWithTempShift
+          previousCycles: [cycleWithTempShift]
         })
 
         expect(Object.keys(status.phases).length).to.eql(3)
@@ -149,7 +149,7 @@ describe('sympto', () => {
     it('with fhM + mucus peak on same day finds correct start of post-ovu phase', () => {
       const status = getSensiplanStatus({
         cycle: mucusPeakAndFhmOnSameDay,
-        previousCycle: cycleWithTempShift
+        previousCycles: [cycleWithTempShift]
       })
 
       expect(status.temperatureShift).to.be.an('object')
@@ -180,7 +180,7 @@ describe('sympto', () => {
     it('with fhM 2 days before mucus peak waits for end of mucus eval', () => {
       const status = getSensiplanStatus({
         cycle: fhmTwoDaysBeforeMucusPeak,
-        previousCycle: cycleWithTempShift
+        previousCycles: [cycleWithTempShift]
       })
 
       expect(status.temperatureShift).to.be.an('object')
@@ -211,7 +211,7 @@ describe('sympto', () => {
     it('with another mucus peak 5 days after fHM ignores it', () => {
       const status = getSensiplanStatus({
         cycle: mucusPeak5DaysAfterFhm,
-        previousCycle: cycleWithTempShift
+        previousCycles: [cycleWithTempShift]
       })
 
       expect(status.temperatureShift).to.be.an('object')
@@ -242,7 +242,7 @@ describe('sympto', () => {
     it('with mucus peak 2 days before fhM waits for end of temp eval', () => {
       const status = getSensiplanStatus({
         cycle:  mucusPeakTwoDaysBeforeFhm,
-        previousCycle: cycleWithTempShift
+        previousCycles: [cycleWithTempShift]
       })
 
       expect(status.temperatureShift).to.be.an('object')
@@ -273,7 +273,7 @@ describe('sympto', () => {
     it('with mucus peak 5 days before fhM waits for end of temp eval', () => {
       const status = getSensiplanStatus({
         cycle:  fhm5DaysAfterMucusPeak,
-        previousCycle: cycleWithTempShift
+        previousCycles: [cycleWithTempShift]
       })
 
       expect(status.temperatureShift).to.be.an('object')
@@ -302,6 +302,15 @@ describe('sympto', () => {
     })
   })
 
+  describe('applying the minus-8 rule', () => {
+    it('shortens the pre-ovu phase if there is a previous <13 fhm')
+    it('shortens the pre-ovu phase if there is a previous <13 fhm with less than 12 cycles')
+    it('shortens the pre-ovu phase if mucus occurs')
+    it('lengthens the pre-ovu phase if >= 12 cycles')
+    it('does not lengthen the pre-ovu phase if < 12 cycles')
+    it('does not lengthen the pre-ovu phase if < 12 cycles')
+  })
+
   describe('when args are wrong', () => {
     it('throws when arg object is not in right format', () => {
       const wrongObject = { hello: 'world' }
@@ -316,10 +325,10 @@ describe('sympto', () => {
           hello: 'world',
           bleeding: { value: 0 }
         }],
-        previousCycle: [{
+        previousCycles: [[{
           date: '1992-09-09',
           bleeding: { value: 0 }
-        }]
+        }]]
       })).to.throw(AssertionError)
       expect(() => getSensiplanStatus({
         cycle: [{
@@ -327,20 +336,20 @@ describe('sympto', () => {
           temperature: {value: '35'},
           bleeding: { value: 0 }
         }],
-        previousCycle: [{
+        previousCycles: [[{
           date: '1992-09-09',
           bleeding: { value: 0 }
-        }]
+        }]]
       })).to.throw(AssertionError)
       expect(() => getSensiplanStatus({
         cycle: [{
           date: '09-14-2017',
           bleeding: { value: 0 }
         }],
-        previousCycle: [{
+        previousCycles: [[{
           date: '1992-09-09',
           bleeding: { value: 0 }
-        }]
+        }]]
       })).to.throw(AssertionError)
     })
     it('throws if first cycle day does not have bleeding value', () => {
@@ -351,11 +360,11 @@ describe('sympto', () => {
             value: 'medium'
           }
         }],
-        previousCycle: [
+        previousCycles: [[
           {
             date: '2017-09-23',
           }
-        ]
+        ]]
       })).to.throw(AssertionError)
     })
   })
-- 
GitLab