185d6e4e5SJim Jagielski################################################################ 285d6e4e5SJim Jagielski# 385d6e4e5SJim Jagielski# Licensed to the Apache Software Foundation (ASF) under one 485d6e4e5SJim Jagielski# or more contributor license agreements. See the NOTICE file 585d6e4e5SJim Jagielski# distributed with this work for additional information 685d6e4e5SJim Jagielski# regarding copyright ownership. The ASF licenses this file 785d6e4e5SJim Jagielski# to you under the Apache License, Version 2.0 (the 885d6e4e5SJim Jagielski# "License"); you may not use this file except in compliance 985d6e4e5SJim Jagielski# with the License. You may obtain a copy of the License at 1085d6e4e5SJim Jagielski# 1185d6e4e5SJim Jagielski# http://www.apache.org/licenses/LICENSE-2.0 1285d6e4e5SJim Jagielski# 1385d6e4e5SJim Jagielski# Unless required by applicable law or agreed to in writing, 1485d6e4e5SJim Jagielski# software distributed under the License is distributed on an 1585d6e4e5SJim Jagielski# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1685d6e4e5SJim Jagielski# KIND, either express or implied. See the License for the 1785d6e4e5SJim Jagielski# specific language governing permissions and limitations 1885d6e4e5SJim Jagielski# under the License. 1985d6e4e5SJim Jagielski"""Error kinds of the extended save modes. Those modes write extension content on purpose, so their output is not expected to be 2085d6e4e5SJim Jagielskischema valid; what must not happen is that it gets worse. A baseline per (mode, schema) lists the documents it covers and each 2185d6e4e5SJim Jagielskikind of error (the message with the expected-alternatives tail removed) with its count and the packages that have it. A run is 2285d6e4e5SJim Jagielskiworse when a kind is new, a count or a package count went up, or a baseline document is no longer covered. Only documents the 2385d6e4e5SJim Jagielskitests build or create are used: the ones an install ships differ from install to install.""" 2485d6e4e5SJim Jagielskiimport json 2585d6e4e5SJim Jagielskiimport re 2685d6e4e5SJim Jagielski 2785d6e4e5SJim Jagielskifrom aootest.checkers import compare, report 2885d6e4e5SJim Jagielskifrom aootest.paths import DATA 2985d6e4e5SJim Jagielski 3085d6e4e5SJim JagielskiBASELINE = DATA / "baseline" 31*2c760c13SJim Jagielski# (save mode, schema): 12, 13 and 14 are the plain schemas, 12x, 13x and 14x the same with foreign content removed first 32*2c760c13SJim JagielskiPAIRS = (("ext", "12"), ("ext", "12x"), ("x13", "13"), ("x13", "13x"), ("x14", "14"), ("x14", "14x")) 3385d6e4e5SJim JagielskiSTABLE_PREFIXES = ("built/", "generated/") 3485d6e4e5SJim Jagielski 3585d6e4e5SJim Jagielski 3685d6e4e5SJim Jagielskidef stable(sources): 3785d6e4e5SJim Jagielski """The sources whose files do not depend on the install.""" 3885d6e4e5SJim Jagielski return [s for s in sources if s.id.startswith(STABLE_PREFIXES)] 3985d6e4e5SJim Jagielski 4085d6e4e5SJim Jagielski 4185d6e4e5SJim Jagielskidef kinds_of(val, version, packages): 4285d6e4e5SJim Jagielski """The kinds of the errors that validate.check() found against `version` in the named packages. A jing failure that names 4385d6e4e5SJim Jagielski the work directory is grouped under one key, whatever the directory was.""" 4485d6e4e5SJim Jagielski entries = [e for e in val["errors"][version] if e[0].split("/", 1)[0] in packages] 4585d6e4e5SJim Jagielski res = {} 4685d6e4e5SJim Jagielski for key, v in report.kinds_of({"errors": {version: entries}}, version).items(): 4785d6e4e5SJim Jagielski key = re.sub(r"/[^ ]*/w-validate", "<workdir>", key) 4885d6e4e5SJim Jagielski old = res.setdefault(key, {"errors": 0, "packages": []}) 4985d6e4e5SJim Jagielski old["errors"] += v["errors"] 5085d6e4e5SJim Jagielski old["packages"] = sorted(set(old["packages"]) | set(v["packages"])) 5185d6e4e5SJim Jagielski return res 5285d6e4e5SJim Jagielski 5385d6e4e5SJim Jagielski 5485d6e4e5SJim Jagielskidef path(mode, version): 5585d6e4e5SJim Jagielski return BASELINE / ("kinds-%s-%s.json" % (mode, version)) 5685d6e4e5SJim Jagielski 5785d6e4e5SJim Jagielski 5885d6e4e5SJim Jagielskidef load(mode, version): 5985d6e4e5SJim Jagielski p = path(mode, version) 6085d6e4e5SJim Jagielski return json.loads(p.read_text(encoding="utf-8")) if p.exists() else None 6185d6e4e5SJim Jagielski 6285d6e4e5SJim Jagielski 6385d6e4e5SJim Jagielskidef write(mode, version, documents, kinds): 6485d6e4e5SJim Jagielski BASELINE.mkdir(exist_ok=True) 6585d6e4e5SJim Jagielski path(mode, version).write_text(json.dumps({"documents": sorted(documents), "kinds": kinds}, indent=1, sort_keys=True) + "\n", encoding="utf-8") 6685d6e4e5SJim Jagielski 6785d6e4e5SJim Jagielski 6885d6e4e5SJim Jagielskidef judge(baseline, documents, kinds): 6985d6e4e5SJim Jagielski """(lines, bad): how `kinds` of the run differ from the baseline, and whether it is worse.""" 7085d6e4e5SJim Jagielski missing = sorted(set(baseline["documents"]) - set(documents)) 7185d6e4e5SJim Jagielski lines, bad = compare.compare(baseline["kinds"], kinds) 7285d6e4e5SJim Jagielski return ["NOT COVERED " + d for d in missing] + lines, bool(missing) or bad 73