1*0e16a31dSJim Jagielski#************************************************************** 2*0e16a31dSJim Jagielski# 3*0e16a31dSJim Jagielski# Licensed to the Apache Software Foundation (ASF) under one 4*0e16a31dSJim Jagielski# or more contributor license agreements. See the NOTICE file 5*0e16a31dSJim Jagielski# distributed with this work for additional information 6*0e16a31dSJim Jagielski# regarding copyright ownership. The ASF licenses this file 7*0e16a31dSJim Jagielski# to you under the Apache License, Version 2.0 (the 8*0e16a31dSJim Jagielski# "License"); you may not use this file except in compliance 9*0e16a31dSJim Jagielski# with the License. You may obtain a copy of the License at 10*0e16a31dSJim Jagielski# 11*0e16a31dSJim Jagielski# http://www.apache.org/licenses/LICENSE-2.0 12*0e16a31dSJim Jagielski# 13*0e16a31dSJim Jagielski# Unless required by applicable law or agreed to in writing, 14*0e16a31dSJim Jagielski# software distributed under the License is distributed on an 15*0e16a31dSJim Jagielski# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*0e16a31dSJim Jagielski# KIND, either express or implied. See the License for the 17*0e16a31dSJim Jagielski# specific language governing permissions and limitations 18*0e16a31dSJim Jagielski# under the License. 19*0e16a31dSJim Jagielski# 20*0e16a31dSJim Jagielski#************************************************************** 21*0e16a31dSJim Jagielski 22*0e16a31dSJim Jagielski# usage: make-doctype-controls.py -- (re)generate doctypecheck.py's negative-control documents in fixtures/control-doctype/ 23*0e16a31dSJim Jagielski# .expected.json maps each document to the (level, rule) pairs doctypecheck.py must report, exactly. 24*0e16a31dSJim Jagielskiimport json, os, shutil, zipfile 25*0e16a31dSJim Jagielski 26*0e16a31dSJim JagielskiC = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures", "control-doctype") 27*0e16a31dSJim JagielskiP = "application/vnd.oasis.opendocument." 28*0e16a31dSJim JagielskiNS = ('xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML"') 29*0e16a31dSJim JagielskiS, Z = zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED 30*0e16a31dSJim JagielskiEXPECTED = {} 31*0e16a31dSJim Jagielski 32*0e16a31dSJim Jagielski 33*0e16a31dSJim Jagielskidef content(child="text", root="office:document-content", extra=""): 34*0e16a31dSJim Jagielski body = "<office:body>%s</office:body>" % ("<office:%s/>" % child if child else "") 35*0e16a31dSJim Jagielski return '<?xml version="1.0" encoding="UTF-8"?>\n<%s %s office:version="1.2"%s>%s</%s>\n' % (root, NS, extra, body, root) 36*0e16a31dSJim Jagielski 37*0e16a31dSJim Jagielski 38*0e16a31dSJim JagielskiMATHDOC = '<?xml version="1.0" encoding="UTF-8"?>\n<math:math %s><math:mi>x</math:mi></math:math>\n' % NS 39*0e16a31dSJim Jagielski 40*0e16a31dSJim Jagielski 41*0e16a31dSJim Jagielskidef pkg(name, mime, body, expect=(), files=None, manifest=""): 42*0e16a31dSJim Jagielski """files: replaces the default content.xml; manifest: extra file-entry elements.""" 43*0e16a31dSJim Jagielski with zipfile.ZipFile(os.path.join(C, name + ".odt"), "w") as z: 44*0e16a31dSJim Jagielski if mime is not None: 45*0e16a31dSJim Jagielski z.writestr(zipfile.ZipInfo("mimetype"), mime, compress_type=S) 46*0e16a31dSJim Jagielski for n, d in (files if files is not None else {"content.xml": body}).items(): 47*0e16a31dSJim Jagielski z.writestr(n, d, compress_type=Z) 48*0e16a31dSJim Jagielski z.writestr("META-INF/manifest.xml", '<?xml version="1.0" encoding="UTF-8"?>\n<manifest:manifest xmlns:manifest=' 49*0e16a31dSJim Jagielski '"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">%s</manifest:manifest>\n' % manifest, compress_type=Z) 50*0e16a31dSJim Jagielski EXPECTED[name + ".odt"] = sorted(expect) 51*0e16a31dSJim Jagielski 52*0e16a31dSJim Jagielski 53*0e16a31dSJim Jagielskidef flat(name, mime, child="text", expect=()): 54*0e16a31dSJim Jagielski attr = "" if mime is None else ' office:mimetype="%s"' % mime 55*0e16a31dSJim Jagielski open(os.path.join(C, name + ".fodt"), "w").write(content(child, "office:document", attr)) 56*0e16a31dSJim Jagielski EXPECTED[name + ".fodt"] = sorted(expect) 57*0e16a31dSJim Jagielski 58*0e16a31dSJim Jagielski 59*0e16a31dSJim Jagielskishutil.rmtree(C, ignore_errors=True) 60*0e16a31dSJim Jagielskios.makedirs(C) 61*0e16a31dSJim Jagielskifor t, ms, child in (("text", ["text", "text-template", "text-master"], "text"), ("spreadsheet", ["spreadsheet", "spreadsheet-template"], "spreadsheet"), 62*0e16a31dSJim Jagielski ("drawing", ["graphics", "graphics-template"], "drawing"), ("presentation", ["presentation", "presentation-template"], "presentation"), 63*0e16a31dSJim Jagielski ("chart", ["chart", "chart-template"], "chart"), ("image", ["image", "image-template"], "image"), ("database", ["base"], "database")): 64*0e16a31dSJim Jagielski for m in ms: 65*0e16a31dSJim Jagielski pkg("good-" + m, P + m, content(child)) 66*0e16a31dSJim Jagielskipkg("good-formula", P + "formula", MATHDOC) 67*0e16a31dSJim Jagielskisub = lambda mt, c: {"content.xml": content(), "Object 1/content.xml": c} 68*0e16a31dSJim Jagielskient = lambda mt: '<manifest:file-entry manifest:full-path="Object 1/" manifest:media-type="%s"/>' % mt 69*0e16a31dSJim Jagielskipkg("good-embedded", P + "text", None, files=sub(P + "chart", content("chart")), manifest=ent(P + "chart")) 70*0e16a31dSJim Jagielskipkg("good-embedded-math", P + "text", None, files=sub("", MATHDOC), manifest=ent(P + "formula")) 71*0e16a31dSJim Jagielskiflat("good-flat", P + "text") 72*0e16a31dSJim Jagielskifor m, ru in (("application/x-bogus", "doctype-unknown-mimetype"), (P + "text\n", "doctype-unknown-mimetype"), 73*0e16a31dSJim Jagielski ("application.vnd.oasis.opendocument.graphics", "doctype-unknown-mimetype"), 74*0e16a31dSJim Jagielski (P + "text-web", "doctype-unlisted-mimetype"), (P + "formula-template", "doctype-unlisted-mimetype")): 75*0e16a31dSJim Jagielski pkg("bad-mime-" + str(len(EXPECTED)), m, content(), [("shall", ru)]) 76*0e16a31dSJim Jagielskipkg("no-mimetype", None, content(), [("shall", "doctype-no-mimetype")]) 77*0e16a31dSJim Jagielskipkg("body-mismatch", P + "text", content("spreadsheet"), [("shall", "doctype-body")]) 78*0e16a31dSJim Jagielskipkg("body-empty", P + "text", content(None), [("shall", "doctype-body")]) 79*0e16a31dSJim Jagielskipkg("root-styles", P + "text", content(root="office:document-styles"), [("shall", "doctype-root")]) 80*0e16a31dSJim Jagielskipkg("formula-wrong-root", P + "formula", content(), [("shall", "doctype-root")]) 81*0e16a31dSJim Jagielskipkg("math-in-text", P + "text", MATHDOC, [("shall", "doctype-root")]) 82*0e16a31dSJim Jagielskipkg("only-styles", P + "text", None, [("shall", "doctype-no-body")], files={"styles.xml": content(None, "office:document-styles")}) 83*0e16a31dSJim Jagielskipkg("only-meta", P + "text", None, [("shall", "doctype-no-content"), ("shall", "doctype-no-body")], files={"meta.xml": "<a/>"}) 84*0e16a31dSJim Jagielskipkg("malformed", P + "text", "<office:document-content", [("shall", "doctype-malformed")]) 85*0e16a31dSJim Jagielskipkg("sub-body", P + "text", None, [("should", "sub-doctype-body")], files=sub(P + "chart", content("spreadsheet")), manifest=ent(P + "chart")) 86*0e16a31dSJim Jagielskipkg("sub-root", P + "text", None, [("should", "sub-doctype-root")], files=sub(P + "formula", content()), manifest=ent(P + "formula")) 87*0e16a31dSJim Jagielskiflat("flat-no-mimetype", None, expect=[("shall", "doctype-no-mimetype")]) 88*0e16a31dSJim Jagielskiflat("flat-unknown", "application/x-bogus", expect=[("shall", "doctype-unknown-mimetype")]) 89*0e16a31dSJim Jagielskiflat("flat-formula-mime", P + "formula", expect=[("shall", "doctype-unknown-mimetype")]) 90*0e16a31dSJim Jagielskiflat("flat-body", P + "text", "presentation", [("shall", "doctype-body")]) 91*0e16a31dSJim Jagielskijson.dump(EXPECTED, open(os.path.join(C, ".expected.json"), "w"), indent=1) 92