xref: /trunk/test/aoo-test/src/aootest_worker/ops/calcval.py (revision 2cb6d6f119bbe2f78742f1c5c8538cb0d4e72ede)
1################################################################
2#
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#    http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing,
14#  software distributed under the License is distributed on an
15#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16#  KIND, either express or implied.  See the License for the
17#  specific language governing permissions and limitations
18#  under the License.
19
20"""Evaluates formulas in a new Calc document. The data area the cases refer to is described at the top of
21data/calcval-cases.tsv. Ported from the ODF harness's calcval.py."""
22import math
23
24from aootest.calcval import api_formula, parse_mode
25from aootest_worker.ops import core
26
27
28def _num(v):
29    return v if math.isfinite(v) else repr(v)
30
31
32def cell_result(cell):
33    try:
34        rt = cell.getPropertyValue("FormulaResultType").value
35    except Exception:
36        rt = None
37    return {"rt": rt, "err": cell.getError(), "str": cell.getString(), "val": _num(float(cell.getValue()))}
38
39
40def setup_data(doc):
41    sheets = doc.getSheets()
42    sheets.insertNewByName("Other", 1)
43    sh = sheets.getByIndex(0)
44
45    def put(addr, vals):
46        a0 = sh.getCellRangeByName(addr).getRangeAddress()
47        for r, row in enumerate(vals):
48            for c, v in enumerate(row):
49                if v is None:
50                    continue
51                cell = sh.getCellByPosition(a0.StartColumn + c, a0.StartRow + r)
52                if isinstance(v, str):
53                    cell.setString(v)
54                else:
55                    cell.setValue(v)
56
57    put("A1", [[v] for v in "yxxyxyxxy"])
58    put("B1", [[v] for v in "yxyyyyxyx"])
59    put("D1", [[10 * i, 11 * i, 101 * i] for i in range(1, 6)])
60    put("H1", [[10 * i for i in range(1, 6)], [11 * i for i in range(1, 6)], [101 * i for i in range(1, 6)]])
61    put("N1", [[v] for v in (3, 5, 8, 9, 13, 14)])
62    put("O1", [[v] for v in (1, 2, 3, 4, 5, 6)])
63    put("P1", [[v] for v in (2, 4, 7, 15, 30, 58)])
64    put("R1", [["Name", "Age", "Score"], ["A", 20, 5], ["B", 30, "n/a"], ["C", 40, 15], ["D", 50, None], ["E", 60, 25]])
65    put("V1", [["Age"], [">=30"]])
66    put("W1", [["Age"], [None]])
67    put("Y1", [["Name"], ["A"]])
68    put("AH1", [[v] for v in (6, 6, 6, 6, 3, 2, 1, 2, 6, 4, 2)])
69    put("AI1", [[v] for v in (1, 3, 5)])
70    put("AJ1", [[v] for v in (2, 4, 7, 9)])
71    put("AK1", [[v] for v in (2, 4, 7, 9)])
72    return sh
73
74
75def calc_eval(cases):
76    """Sets each case's formula in a fresh Calc document and returns {"cases": [{"id", "result", "readback"} or
77    {"id", "exception"}], "aborted_at": id or None}. The scratch area AA1:AF12 is cleared after every case."""
78    doc = core._desktop().loadComponentFromURL("private:factory/scalc", "_blank", 0, (core.pv("Hidden", True),))
79    if doc is None:
80        raise core.Fail("uno", "could not create a Calc document")
81    results, aborted = [], None
82    try:
83        sh = setup_data(doc)
84        scratch = sh.getCellRangeByName("AA1:AF12")
85        for case in cases:
86            kind, cols, rows, row = parse_mode(case["mode"])
87            rec = {"id": case["id"]}
88            try:
89                formula = api_formula(case["formula"])
90                if kind == "cell":
91                    cell = sh.getCellByPosition(26, row - 1)
92                    cell.setFormula(formula)
93                    cells = [cell]
94                else:
95                    rng = sh.getCellRangeByPosition(26, 0, 26 + cols - 1, rows - 1)
96                    rng.setArrayFormula(formula)
97                    cells = [sh.getCellByPosition(26 + c, r) for r in range(rows) for c in range(cols)]
98                doc.calculateAll()
99                rec["result"] = [cell_result(c) for c in cells]
100                rec["readback"] = cells[0].getFormula()
101            except Exception as e:
102                rec["exception"] = "%s: %s" % (type(e).__name__, e)
103                if "Disposed" in type(e).__name__ or "connect" in str(e).lower():
104                    aborted = case["id"]
105            results.append(rec)
106            try:
107                scratch.clearContents(1 | 2 | 4 | 8 | 16 | 32)
108            except Exception as e:
109                aborted = aborted or case["id"]
110                rec["exception"] = rec.get("exception", "") + " clear: %s" % e
111            if aborted:
112                break
113    finally:
114        core._close(doc)
115    return {"cases": results, "aborted_at": aborted}
116
117
118OPS = {"calc_eval": core.guarded(calc_eval)}
119