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# 21# usage: runpy.sh fixtures/styles-gfx/verify.py <port> <outdir> 22# Reloads the packages written by make.py and compares the properties of shapes and styles with the values make.py set. 23import sys, os 24import tempfile 25OUT = os.path.abspath(sys.argv[2]) 26sys.argv = [sys.argv[0], sys.argv[1], tempfile.mkdtemp(prefix="styles-gfx-verify-")] 27exec(open("fixtures/styles-gfx/make.py").read().split("\nDOCS = [")[0]) 28bad, checked = [], [0] 29 30 31def same(a, b, k=""): 32 if k.endswith("Color") or k.endswith("Color2"): 33 return (a & 0xffffff) == (b & 0xffffff) 34 if isinstance(b, uno.Enum): 35 return isinstance(a, uno.Enum) and a.value == b.value 36 if isinstance(b, float): 37 return abs(a - b) < 1e-3 * max(1.0, abs(b)) 38 if hasattr(b, "OuterLineWidth"): 39 return (a.Color & 0xffffff) == (b.Color & 0xffffff) and (a.InnerLineWidth > 0) == (b.InnerLineWidth > 0) and \ 40 abs(a.OuterLineWidth + a.InnerLineWidth + a.LineDistance - b.OuterLineWidth - b.InnerLineWidth - b.LineDistance) <= 8 41 if hasattr(b, "ShadowWidth"): 42 return a.Location.value == b.Location.value 43 if isinstance(b, bool): 44 return bool(a) == b 45 if isinstance(b, int) and isinstance(a, int) and abs(b) >= 50: 46 return abs(a - b) <= 2 47 return a == b 48 49 50def cmp(tag, obj, props): 51 for k, v in props.items(): 52 try: 53 a = obj.getPropertyValue(k) 54 except Exception: 55 continue 56 checked[0] += 1 57 try: 58 ok = same(a, v, k) 59 except Exception as e: 60 ok = False 61 if not ok: 62 bad.append((tag, k, v.value if isinstance(v, uno.Enum) else v, a.value if isinstance(a, uno.Enum) else a)) 63 64 65def loaddoc(name): 66 return desk.loadComponentFromURL(uno.systemPathToFileUrl(os.path.join(OUT, name)), "_blank", 0, 67 (pv("Hidden", True), pv("ReadOnly", True))) 68 69 70def shapes(page): 71 return [page.getByIndex(i) for i in range(page.Count)] 72 73 74def draw_check(): 75 d = loaddoc("draw-fill-line.odg") 76 sh = shapes(d.DrawPages.getByIndex(0)) 77 cases = fillprops() + linecases() 78 for s, (n, p) in zip(sh, cases): 79 cmp("draw-fill-line " + n, s, {k: v for k, v in p.items() if not k.endswith("Name") and k not in ("FillBitmapOffsetX", "FillBitmapOffsetY")}) 80 print("draw-fill-line shapes", len(sh), "cases", len(cases)) 81 d.close(True) 82 83 84def style_check(doc_name, fam, prefix, cases): 85 d = loaddoc(doc_name) 86 st_ = d.StyleFamilies.getByName(fam) 87 for n, p in cases: 88 nm = prefix + n 89 if st_.hasByName(nm): 90 cmp(doc_name + " " + nm, st_.getByName(nm), p) 91 else: 92 bad.append((doc_name, nm, "style missing", "")) 93 d.close(True) 94 95 96def writer_pagestyle_check(): 97 d = loaddoc("writer-pagestyles.odt") 98 fam = d.StyleFamilies.getByName("PageStyles") 99 for wm in range(5): 100 cmp("ps-wm-%d" % wm, fam.getByName("ps-wm-%d" % wm), dict(WritingMode=wm)) 101 for lay in ("ALL", "LEFT", "RIGHT", "MIRRORED"): 102 cmp("ps-layout-" + lay, fam.getByName("ps-layout-" + lay), dict(PageStyleLayout=E("com.sun.star.style.PageStyleLayout", lay))) 103 for nt in (0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 20, 30, 40): 104 cmp("ps-num-%d" % nt, fam.getByName("ps-num-%d" % nt), dict(NumberingType=nt)) 105 for gm in (0, 1, 2): 106 for std in (True, False): 107 cmp("ps-grid-%d-%d" % (gm, std), fam.getByName("ps-grid-%s-%d" % (gm, std)), dict(GridMode=gm, RubyBelow=not std, GridPrint=not std, GridDisplay=bool(std))) 108 for i in range(6): 109 cmp("ps-hf-%d" % i, fam.getByName("ps-hf-%d" % i), dict(page_common(i), **hf_props("Header", i))) 110 d.close(True) 111 112 113def impress_check(): 114 d = loaddoc("impress-effects.odp") 115 pages = d.DrawPages 116 spd = ("SLOW", "MEDIUM", "FAST") 117 effects = enum_names("com.sun.star.presentation.FadeEffect") 118 for i in range(pages.Count): 119 pg = pages.getByIndex(i) 120 cmp("slide %d" % i, pg, dict(Speed=E("com.sun.star.presentation.AnimationSpeed", spd[i % 3]), Change=i % 3, Duration=1 + i % 5, 121 Visible=bool(i % 4), IsBackgroundVisible=bool(i % 3), IsBackgroundObjectsVisible=bool(i % 5), IsFooterVisible=bool(i % 3), 122 IsPageNumberVisible=bool(i % 4), IsDateTimeVisible=bool(i % 5))) 123 print("impress-effects slides", pages.Count) 124 d.close(True) 125 d = loaddoc("impress-transitions.odp") 126 pages = d.DrawPages 127 print("impress-transitions slides", pages.Count) 128 for i in range(pages.Count): 129 pg = pages.getByIndex(i) 130 try: 131 checked[0] += 1 132 if pg.getPropertyValue("TransitionType") == 0 and i < 38: 133 bad.append(("impress-transitions", "slide %d" % i, "TransitionType>0", 0)) 134 except Exception: 135 pass 136 d.close(True) 137 138 139def calc_check(): 140 cases = [] 141 d = loaddoc("calc-cells.ods") 142 fam = d.StyleFamilies.getByName("CellStyles") 143 names = [n for n in fam.ElementNames if n.startswith("cs-")] 144 print("calc cell styles", len(names)) 145 d.close(True) 146 147 148for fn in (draw_check, writer_pagestyle_check, impress_check, calc_check): 149 try: 150 fn() 151 except Exception as e: 152 print("FAIL", fn.__name__, type(e).__name__, str(e)[:120]) 153shutil.rmtree(work, ignore_errors=True) 154shutil.rmtree(out, ignore_errors=True) 155print("checked", checked[0], "mismatches", len(bad)) 156for b in bad: 157 print("MISMATCH", *b) 158