<commit_before>package ee.tuleva.onboarding.comparisons.returns

import ee.tuleva.onboarding.comparisons.fundvalue.FundValue
import ee.tuleva.onboarding.comparisons.fundvalue.FundValueProvider
import ee.tuleva.onboarding.comparisons.fundvalue.retrieval.EPIFundValueRetriever
import ee.tuleva.onboarding.comparisons.fundvalue.retrieval.UnionStockIndexRetriever
import ee.tuleva.onboarding.comparisons.overview.AccountOverview
import ee.tuleva.onboarding.comparisons.overview.Transaction
import spock.lang.Specification

import java.time.Instant
import java.time.LocalDate
import java.time.ZoneOffset

class RateOfReturnCalculatorSpec extends Specification {

  FundValueProvider fundValueProvider
  RateOfReturnCalculator rateOfReturnCalculator

  void setup() {
    fundValueProvider = Mock(FundValueProvider)
    rateOfReturnCalculator = new RateOfReturnCalculator(fundValueProvider)
  }

  def "it successfully calculates a return of 0%"() {
    given:
    Instant startTime = parseInstant("2018-06-17")
    Instant endTime = parseInstant("2018-06-18")
    fakeNoReturnFundValues()
    def overview = new AccountOverview([
        new Transaction(100.0, startTime),
        new Transaction(100.0, startTime),
    ], 0.0, 200.0, startTime, endTime, 2)
    when:
    double actualRateOfReturn = rateOfReturnCalculator.getRateOfReturn(overview)
    double estonianAverageRateOfReturn =
        rateOfReturnCalculator.getRateOfReturn(overview, EPIFundValueRetriever.KEY)
    double marketAverageRateOfReturn =
        rateOfReturnCalculator.getRateOfReturn(overview, UnionStockIndexRetriever.KEY)

    then:
    actualRateOfReturn == 0
    estonianAverageRateOfReturn == 0
    marketAverageRateOfReturn == 0
  }

  def "it successfully calculates a return for 0-valued transactions"() {
    given:
    Instant startTime = parseInstant("2018-06-17")
    Instant endTime = parseInstant("2018-06-18")
    fakeNoReturnFundValues()
    def overview = new AccountOverview([
        new Transaction(firstTransaction, startTime),
        new Transaction(secondTransaction, startTime),
    ], beginningBalance, endingBalance, startTime, endTime, 2)
    when:
    double actualRateOfReturn = rateOfReturnCalculator.getRateOfReturn(overview)
    double estonianAverageRateOfReturn =
        rateOfReturnCalculator.getRateOfReturn(overview, EPIFundValueRetriever.KEY)
    double marketAverageRateOfReturn =
        rateOfReturnCalculator.getRateOfReturn(overview, UnionStockIndexRetriever.KEY)
    then:
    actualRateOfReturn == xirr.doubleValue()
    estonianAverageRateOfReturn == 0
    marketAverageRateOfReturn == 0
    where:
    firstTransaction | secondTransaction | beginningBalance | endingBalance || xirr
    0.0              | 0.0               | 0.0              | 0.0           || 0.0
    0.0              | 1.0               | 0.0              | 1.0           || 0.0
    0.0              | -1.0              | 1.0              | 0.0           || 0.0
  }

  def "it correctly calculates actual return taking into account the beginning balance"() {
    given:
    fakeNoReturnFundValues()

    Instant startTime = parseInstant("2010-01-01")<commit_msg>WIP: Adds 0 transaction and rate tests for cash calculation<commit_after>package ee.tuleva.onboarding.comparisons.returns

import ee.tuleva.onboarding.comparisons.fundvalue.FundValue
import ee.tuleva.onboarding.comparisons.fundvalue.FundValueProvider
import ee.tuleva.onboarding.comparisons.fundvalue.retrieval.EPIFundValueRetriever
import ee.tuleva.onboarding.comparisons.fundvalue.retrieval.UnionStockIndexRetriever
import ee.tuleva.onboarding.comparisons.overview.AccountOverview
import ee.tuleva.onboarding.comparisons.overview.Transaction
import spock.lang.Specification

import java.time.Instant
import java.time.LocalDate
import java.time.ZoneOffset

class RateOfReturnCalculatorSpec extends Specification {

  FundValueProvider fundValueProvider
  RateOfReturnCalculator rateOfReturnCalculator

  void setup() {
    fundValueProvider = Mock(FundValueProvider)
    rateOfReturnCalculator = new RateOfReturnCalculator(fundValueProvider)
  }

  def "it successfully calculates a return of 0%"() {
    given:
    Instant startTime = parseInstant("2018-06-17")
    Instant endTime = parseInstant("2018-06-18")
    fakeNoReturnFundValues()
    def overview = new AccountOverview([
        new Transaction(100.0, startTime),
        new Transaction(100.0, startTime),
    ], 0.0, 200.0, startTime, endTime, 2)
    when:
    double actualRateOfReturn = rateOfReturnCalculator.getRateOfReturn(overview)
    double estonianAverageRateOfReturn =
        rateOfReturnCalculator.getRateOfReturn(overview, EPIFundValueRetriever.KEY)
    double marketAverageRateOfReturn =
        rateOfReturnCalculator.getRateOfReturn(overview, UnionStockIndexRetriever.KEY)

    BigDecimal cashReturn = rateOfReturnCalculator.getCashReturn(overview)
    BigDecimal cashReturnWhenInvestingInEstonianAverageFund =
        rateOfReturnCalculator.getCashReturn(overview, EPIFundValueRetriever.KEY).orElseThrow()
    BigDecimal cashReturnWhenInvestingInTheWorldMarket =
        rateOfReturnCalculator.getCashReturn(overview, UnionStockIndexRetriever.KEY).orElseThrow()

    then:
    actualRateOfReturn == 0
    estonianAverageRateOfReturn == 0
    marketAverageRateOfReturn == 0
    cashReturn == 0
    cashReturnWhenInvestingInEstonianAverageFund == 0
    cashReturnWhenInvestingInTheWorldMarket == 0
  }

  def "it successfully calculates a return for 0-valued transactions"() {
    given:
    Instant startTime = parseInstant("2018-06-17")
    Instant endTime = parseInstant("2018-06-18")
    fakeNoReturnFundValues()
    def overview = new AccountOverview([
        new Transaction(firstTransaction, startTime),
        new Transaction(secondTransaction, startTime),
    ], beginningBalance, endingBalance, startTime, endTime, 2)
    when:
    double actualRateOfReturn = rateOfReturnCalculator.getRateOfReturn(overview)
    double estonianAverageRateOfReturn =
        rateOfReturnCalculator.getRateOfReturn(overview, EPIFundValueRetriever.KEY)
    double marketAverageRateOfReturn =
        rateOfReturnCalculator.getRateOfReturn(overview, UnionStockIndexRetriever.KEY)
    BigDecimal cashReturn = rateOfReturnCalculator.getCashReturn(overview)
    BigDecimal cashReturnWhenInvestingInEstonianAverageFund =
        rateOfReturnCalculator.getCashReturn(overview, EPIFundValueRetriever.KEY).orElseThrow()
    BigDecimal cashReturnWhenInvestingInTheWorldMarket =
        rateOfReturnCalculator.getCashReturn(overview, UnionStockIndexRetriever.KEY).orElseThrow()
    then:
    actualRateOfReturn == xirr.doubleValue()
    estonianAverageRateOfReturn == 0
    marketAverageRateOfReturn == 0
    cashReturn == 0
    cashReturnWhenInvestingInEstonianAverageFund == 0
    cashReturnWhenInvestingInTheWorldMarket == 0
    where:
    firstTransaction | secondTransaction | beginningBalance | endingBalance || xirr
    0.0              | 0.0               | 0.0              | 0.0           || 0.0
    0.0              | 1.0               | 0.0              | 1.0           || 0.0
    0.0              | -1.0              | 1.0              | 0.0           || 0.0
  }

  def "it correctly calculates actual return taking into account the beginning balance"() {
    given:
    fakeNoReturnFundValues()

    Instant startTime = parseInstant("2010-01-01")
{'fraction_non_alphanumeric': 0.0752746507527465, 'fraction_numerical': 0.026176590261765904, 'mean_word_length': 3.7482292337411462, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1798134', 'n_tokens_mistral': 2359, 'n_tokens_neox': 2102, 'n_words': 394}