summaryrefslogtreecommitdiffstats
path: root/src/libixion/ixion_test_track_deps.cpp
blob: 95875f69837f52d588bbd571b5f781922b4cc54b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "test_global.hpp" // This must be the first header to be included.

#include <ixion/model_context.hpp>
#include <ixion/macros.hpp>
#include <ixion/formula_name_resolver.hpp>
#include <ixion/formula.hpp>

#include <cassert>
#include <iostream>

using namespace ixion;
using namespace std;

void test_single_cell_dependency()
{
    IXION_TEST_FUNC_SCOPE;

    model_context cxt{{400, 200}};
    cxt.append_sheet("One");

    auto resolver = formula_name_resolver::get(formula_name_resolver_t::excel_a1, &cxt);

    cxt.set_numeric_cell(abs_address_t(0,0,0), 1.0);  // A1

    // A2
    abs_address_t pos(0,1,0);
    formula_tokens_t tokens = parse_formula_string(cxt, pos, *resolver, "A1*2");
    formula_tokens_store_ptr_t store = formula_tokens_store::create();
    store->get() = std::move(tokens);
    cxt.set_formula_cell(pos, store);
    register_formula_cell(cxt, pos);

    // A3
    pos.row = 2;
    tokens = parse_formula_string(cxt, pos, *resolver, "A2*2");
    store = formula_tokens_store::create();
    store->get() = std::move(tokens);
    cxt.set_formula_cell(pos, store);
    register_formula_cell(cxt, pos);

    // If A1 is modified, then both A2 and A3 should get updated.
    abs_address_set_t mod_cells = {
        { 0, 0, 0 }
    };

    abs_address_set_t cells = query_dirty_cells(cxt, mod_cells);

    assert(cells.size() == 2);
    assert(cells.count(abs_address_t(0,1,0)) == 1);
    assert(cells.count(abs_address_t(0,2,0)) == 1);
}

void test_range_dependency()
{
    IXION_TEST_FUNC_SCOPE;

    model_context cxt{{400, 200}};
    cxt.append_sheet("One");

    cxt.set_numeric_cell(abs_address_t(0,0,0), 1.0);  // A1
    cxt.set_numeric_cell(abs_address_t(0,0,0), 2.0);  // A2
    cxt.set_numeric_cell(abs_address_t(0,0,0), 3.0);  // A3

    cxt.set_numeric_cell(abs_address_t(0,0,2), 4.0);  // C1
    cxt.set_numeric_cell(abs_address_t(0,0,2), 5.0);  // D1
    cxt.set_numeric_cell(abs_address_t(0,0,2), 6.0);  // E1

    auto resolver = formula_name_resolver::get(formula_name_resolver_t::excel_a1, &cxt);

    // C5
    abs_address_t pos(0,4,2);
    formula_tokens_t tokens = parse_formula_string(cxt, pos, *resolver, "SUM(A1:A3,C1:E1)");
    auto ts = formula_tokens_store::create();
    ts->get() = std::move(tokens);
    cxt.set_formula_cell(pos, ts);
    register_formula_cell(cxt, pos);

    // A10
    pos.row = 9;
    pos.column = 0;
    tokens = parse_formula_string(cxt, pos, *resolver, "C5*2");
    ts = formula_tokens_store::create();
    ts->get() = std::move(tokens);
    cxt.set_formula_cell(pos, ts);
    register_formula_cell(cxt, pos);

    // If A1 is modified, both C5 and A10 should get updated.
    abs_address_set_t addrs = { abs_address_t(0,0,0) };
    abs_address_set_t cells = query_dirty_cells(cxt, addrs);

    assert(cells.count(abs_address_t(0,4,2)) == 1);
    assert(cells.count(abs_address_t(0,9,0)) == 1);
}

void test_matrix_dependency()
{
    IXION_TEST_FUNC_SCOPE;

    model_context cxt{{400, 200}};
    cxt.append_sheet("One");

    cxt.set_numeric_cell(abs_address_t(0,0,0), 1.0);  // A1
    cxt.set_numeric_cell(abs_address_t(0,0,0), 2.0);  // A2
    cxt.set_numeric_cell(abs_address_t(0,0,0), 3.0);  // A3

    cxt.set_numeric_cell(abs_address_t(0,0,2), 4.0);  // C1
    cxt.set_numeric_cell(abs_address_t(0,0,2), 5.0);  // D1
    cxt.set_numeric_cell(abs_address_t(0,0,2), 6.0);  // E1

    abs_range_t range;
    range.first = abs_address_t(0,4,2); // C5
    range.last  = abs_address_t(0,6,4); // E7

    auto resolver = formula_name_resolver::get(formula_name_resolver_t::excel_a1, &cxt);

    // C5:E7
    formula_tokens_t tokens = parse_formula_string(
        cxt, range.first, *resolver, "MMULT(A1:A3,C1:E1)");

    cxt.set_grouped_formula_cells(range, std::move(tokens));
    register_formula_cell(cxt, range.first); // Register only the top-left cell.

    // A10
    abs_address_t pos(0,9,0);
    tokens = parse_formula_string(cxt, pos, *resolver, "C5*2");
    auto ts = formula_tokens_store::create();
    ts->get() = std::move(tokens);
    cxt.set_formula_cell(pos, ts);
    register_formula_cell(cxt, pos);

    // If A1 is modified, both C5 and A10 should get updated.
    abs_address_set_t addrs = { abs_address_t(0,0,0) };
    abs_address_set_t cells = query_dirty_cells(cxt, addrs);

    assert(cells.count(abs_address_t(0,4,2)) == 1);
    assert(cells.count(abs_address_t(0,9,0)) == 1);
}

int main()
{
    test_single_cell_dependency();
    test_range_dependency();
    test_matrix_dependency();

    return EXIT_SUCCESS;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */