<commit_before># -*- coding: utf-8 -*-

from datetime import datetime, timedelta
import mock

from flask import request
from flask_login import LoginManager, UserMixin, current_user, login_user, logout_user

from flask_bitmapist import (chain_events, get_cohort, get_event_data,
                             mark, mark_event, unmark_event,
                             MonthEvents, WeekEvents, DayEvents, HourEvents)
from flask_bitmapist.extensions.flask_login import mark_login, mark_logout


# import necessary for test_user_login/logout, but unused fails pyflakes
mark_login
mark_logout

now = datetime.utcnow()


# COHORTS

def setup_users(now=None):
    now = now or datetime.utcnow()

    # mark specific events for single user with user_string as user_id
    event_mappings = {
        'i': 'user:logged_in',
        'o': 'user:logged_out',
        'c': 'user:created',
        'u': 'user:updated',
        'd': 'user:deleted',
    }

    users = [
        ('iocud', 11),
        ('iocd',  22),
        ('iou',   33),
        ('icd',   44),
        ('io',    55),
        ('ocud',  66),
        ('cud',   77),
        ('od',    88),
        ('d',     99)
    ]

    for user in users:
        for u in user[0]:
            event_name = event_mappings.get(u, None)
            if event_name:
                mark_event(event_name, user[1])

    return users


def setup_chain_events(time_group='days'):
    addons = {
        'and_o': {'name': 'user:logged_out', 'op': 'and'},
        'and_c': {'name': 'user:created',    'op': 'and'},
        'and_u': {'name': 'user:updated',    'op': 'and'},
        'and_d': {'name': 'user:deleted',    'op': 'and'},
        'or_o':  {'name': 'user:logged_out', 'op': 'or'},
        'or_c':  {'name': 'user:created',    'op': 'or'},
        'or_u':  {'name': 'user:updated',    'op': 'or'},
        'or_d':  {'name': 'user:deleted',    'op': 'or'}
    }
    return setup_users(), addons


@mock.patch('flask_bitmapist.utils.BitOpAnd')
@mock.patch('flask_bitmapist.utils.BitOpOr')
@mock.patch('flask_bitmapist.utils.BitOpXor')
@mock.patch('flask_bitmapist.utils.chain_events')
@mock.patch('flask_bitmapist.utils.YearEvents')
@mock.patch('flask_bitmapist.utils.MonthEvents')
@mock.patch('flask_bitmapist.utils.WeekEvents')
def test_get_cohort(mock_week_events, mock_month_events,
                    mock_year_events, mock_chain_events,
                    mock_bit_op_xor, mock_bit_op_or, mock_bit_op_and):
    # test cohort returns
    from random import randint

    # Generate list of ints to act as user ids;
    # - between calls, should have some duplicate and some distinct
    # - temporarily convert to a set to force unique list items

    def e():
        return list(set([randint(1, 25) for n in range(10)]))

    def ee():
        return [e() for n in range(100)]

    mock_week_events.side_effect = ee()
    mock_month_events.side_effect = ee()
    mock_year_events.side_effect = ee()
    mock_chain_events.side_effect = ee()

    # Simulate BitOpAnd & BitOpOr returns but with lists
    mock_bit_op_and.side_effect = lambda x, y: list(set(x) & set(y))
    mock_bit_op_or.side_effect = lambda x, y: list(set(x) | set(y))<commit_msg>Adding test for cohort values/options<commit_after># -*- coding: utf-8 -*-

from datetime import datetime, timedelta
import mock
from random import randint

from flask import request
from flask_login import LoginManager, UserMixin, current_user, login_user, logout_user

from flask_bitmapist import (chain_events, get_cohort, get_event_data,
                             mark, mark_event, unmark_event,
                             MonthEvents, WeekEvents, DayEvents, HourEvents)
from flask_bitmapist.extensions.flask_login import mark_login, mark_logout


# import necessary for test_user_login/logout, but unused fails pyflakes
mark_login
mark_logout

now = datetime.utcnow()


# COHORTS

def setup_users(now=None):
    now = now or datetime.utcnow()

    # mark specific events for single user with user_string as user_id
    event_mappings = {
        'i': 'user:logged_in',
        'o': 'user:logged_out',
        'c': 'user:created',
        'u': 'user:updated',
        'd': 'user:deleted',
    }

    users = [
        ('iocud', 11),
        ('iocd',  22),
        ('iou',   33),
        ('icd',   44),
        ('io',    55),
        ('ocud',  66),
        ('cud',   77),
        ('od',    88),
        ('d',     99)
    ]

    for user in users:
        for u in user[0]:
            event_name = event_mappings.get(u, None)
            if event_name:
                mark_event(event_name, user[1])

    return users


def setup_chain_events(time_group='days'):
    addons = {
        'and_o': {'name': 'user:logged_out', 'op': 'and'},
        'and_c': {'name': 'user:created',    'op': 'and'},
        'and_u': {'name': 'user:updated',    'op': 'and'},
        'and_d': {'name': 'user:deleted',    'op': 'and'},
        'or_o':  {'name': 'user:logged_out', 'op': 'or'},
        'or_c':  {'name': 'user:created',    'op': 'or'},
        'or_u':  {'name': 'user:updated',    'op': 'or'},
        'or_d':  {'name': 'user:deleted',    'op': 'or'}
    }
    return setup_users(), addons


# Test contents of cohort returns
def test_get_cohort_contents():
    # Generate events to ensure specific cohort returns

    # for cohort @days, m=4, n=4:
    #     6: [[5]   [0]   [0]   [1]   ]
    #     7: [[2]   [1]   [2]   [None]]
    #     0: [[None][None][None][None]]
    #     5: [[4]   [None][None][None]]
    #     --   ----  ----  ----  ----
    #   T 18  11     1     2     1

    # ^^^ as_percent (not with replacement):
    #     6: [[83%] [0%]  [0%]  [17%] ]
    #     7: [[29%] [14%] [29%] [None]]
    #     0: [[None][None][None][None]]
    #     5: [[80%] [None][None][None]]
    #     --   ----  ----  ----  ----
    #   T 18  11     1     2     1

    # ^^^ with_replacement (not as percent):
    #     6: [[5]   [3]   [0]   [1]   ]
    #     7: [[2]   [2]   [4]   [None]]
    #     0: [[None][None][None][None]]
    #     5: [[4]   [None][None][None]]
    #     --   ----  ----  ----  ----
    #   T 18  11     5     4     1

    # TO BUILD: 18 users
    # [[5+0] [0+3] [0+0] [1+0] ]
    # [[2+0] [1+1] [2+2] [None]]
    # [[None][None][None][None]]
    # [[4+0] [None][None][None]]

    # construct events/history based on desired outcomes (see commented tables)

    event1 = 'user:popped'
    event2 = 'user:locked'

    dates = [now - timedelta(days=d) for d in range(4)]
    dates.reverse()

    # users = range(100, 118)
    users_event1 = [
        range(100, 106),
        range(106, 113),
        [],
        range(113, 118)
    ]
    users_event2 = [
        [[100, 101, 102, 103, 104], [100, 101, 102], [], [105]],
        [[106, 107], [107, 108], [106, 107, 109, 110], []],
        [[], [], [], []],
        [[113, 114, 115, 116], [], [], []]
    ]

    # mark constructed events
    for i, row_date in enumerate(dates):
        for user_id in users_event1[i]:
            mark_event(event1, user_id, now=row_date)

        for j in range(len(dates)):
            col_date = row_date + timedelta(days=j)
            for user_id in users_event2[i][j]:
                mark_event(event2, user_id, now=col_date)

    # establish expected cohort returns
    expected_c0 = [
        [5, 0, 0, 1],
        [2, 1, 2, None],
        [None, None, None, None],
        [4, None, None, None]
    ]

    # expected_cp = [
    #     [0, 0, 0, 0],
    #     [0, 0, 0, None],
    #     [0, 0, None, None],
    #     [0, None, None, None]
    # ]

    expected_cr = [
        [5, 3, 0, 1],
        [2, 2, 4, None],
        [None, None, None, None],
        [4, None, None, None]
    ]

    expected_totals = [6, 7, 0, 5]

    # get cohort(s)
    c0, d0, t0 = get_cohort(event1, event2, time_group='days', num_rows=4, num_cols=4)
    # cp, dp, tp = get_cohort(event1, event2, time_group='days', num_rows=4, num_cols=4,
    #                         as_percent=True)
    cr, dr, tr = get_cohort(event1, event2, time_group='days', num_rows=4, num_cols=4,
                            with_replacement=True)

    # assert that returned values match expected values
    assert c0 == expected_c0
    # assert cp == expected_cp
    assert cr == expected_cr

    assert t0 == expected_totals
    # assert tp == expected_totals
    assert tr == expected_totals


# Test structure of cohort returns
@mock.patch('flask_bitmapist.utils.BitOpAnd')
@mock.patch('flask_bitmapist.utils.BitOpOr')
@mock.patch('flask_bitmapist.utils.BitOpXor')
@mock.patch('flask_bitmapist.utils.chain_events')
@mock.patch('flask_bitmapist.utils.YearEvents')
@mock.patch('flask_bitmapist.utils.MonthEvents')
@mock.patch('flask_bitmapist.utils.WeekEvents')
def test_get_cohort_structure(mock_week_events, mock_month_events,
                              mock_year_events, mock_chain_events,
                              mock_bit_op_xor, mock_bit_op_or, mock_bit_op_and):
    # Generate list of ints to act as user ids;
    # - between calls, should have some duplicate and some distinct
    # - temporarily convert to a set to force unique list items

    def e():
        return list(set([randint(1, 25) for n in range(10)]))

    def ee():
        return [e() for n in range(100)]

    mock_week_events.side_effect = ee()
    mock_month_events.side_effect = ee()
    mock_year_events.side_effect = ee()
    mock_chain_events.side_effect = ee()

    # Simulate BitOpAnd & BitOpOr returns but with lists
    mock_bit_op_and.side_effect = lambda x, y: list(set(x) & set(y))
    mock_bit_op_or.side_effect = lambda x, y: list(set(x) | set(y))
{'fraction_non_alphanumeric': 0.15584009993753903, 'fraction_numerical': 0.02977305850510098, 'mean_word_length': 2.3971004243281473, '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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '83334', 'n_tokens_mistral': 3564, 'n_tokens_neox': 3359, 'n_words': 817}