############################################################################## # # Copyright (c) 2002, 2003 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Tests of ZConfig schemas.""" import unittest import ZConfig from ZConfig.tests.support import TestBase, CONFIG_BASE def uppercase(value): return str(value).upper() def appsection(value): return MySection(value) def get_foo(section): return section.foo class MySection: def __init__(self, value): self.conf = value def get_section_attributes(section): L = list(section.getSectionAttributes()) L.sort() return L class SchemaTestCase(TestBase): """Tests of the basic schema support itself.""" def test_minimal_schema(self): schema = self.load_schema_text("") self.assertEqual(len(schema), 0) self.assertRaises(IndexError, lambda schema=schema: schema[0]) self.assertRaises(ZConfig.ConfigurationError, schema.getinfo, "foo") def test_simple(self): schema, conf = self.load_both("simple.xml", "simple.conf") self._verifySimpleConf(conf) def _verifySimpleConf(self,conf): eq = self.assertEqual eq(conf.var1, 'abc') eq(conf.int_var, 12) eq(conf.float_var, 12.02) eq(conf.neg_int, -2) check = self.assert_ check(conf.true_var_1) check(conf.true_var_2) check(conf.true_var_3) check(not conf.false_var_1) check(not conf.false_var_2) check(not conf.false_var_3) def test_app_datatype(self): dtname = __name__ + ".uppercase" schema = self.load_schema_text("""\ abc abc not lower case """ % (dtname, dtname, dtname, dtname)) conf = self.load_config_text(schema, """\ a qwerty c upp c er c case """) eq = self.assertEqual eq(conf.a, 'QWERTY') eq(conf.b, 'ABC') eq(conf.c, ['UPP', 'ER', 'CASE']) eq(conf.d, ['NOT', 'LOWER', 'CASE']) eq(get_section_attributes(conf), ["a", "b", "c", "d"]) def test_app_sectiontype(self): schema = self.load_schema_text("""\
""" % __name__) conf = self.load_config_text(schema, """\ sample 42 """) self.assert_(isinstance(conf, MySection)) o1 = conf.conf.sect self.assert_(isinstance(o1, MySection)) self.assertEqual(o1.conf.sample, 42) def test_empty_sections(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, """\
""") self.assert_(conf.s1 is not None) self.assert_(conf.s2 is not None) self.assertEqual(get_section_attributes(conf), ["s1", "s2"]) def test_deeply_nested_sections(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, """\ key sect3-value key sect2-value """) eq = self.assertEqual eq(conf.sect.sect.sect.key, "type1-value") eq(conf.sect.sect.key, "sect2-value") eq(conf.sect.key, "sect3-value") eq(get_section_attributes(conf), ["sect"]) eq(get_section_attributes(conf.sect), ["key", "sect"]) eq(get_section_attributes(conf.sect.sect), ["key", "sect"]) eq(get_section_attributes(conf.sect.sect.sect), ["key"]) def test_multivalued_keys(self): schema = self.load_schema_text("""\ 1 2 3 4 5 """) conf = self.load_config_text(schema, """\ a foo a bar c 41 c 42 c 43 """, num_handlers=2) L = [] self.handlers({'abc': L.append, 'DEF': L.append}) self.assertEqual(L, [['foo', 'bar'], conf]) L = [] self.handlers({'abc': None, 'DEF': L.append}) self.assertEqual(L, [conf]) self.assertEqual(conf.a, ['foo', 'bar']) self.assertEqual(conf.b, [1, 2]) self.assertEqual(conf.c, [41, 42, 43]) self.assertEqual(conf.d, []) self.assertEqual(get_section_attributes(conf), ["a", "b", "c", "d"]) def test_multikey_required(self): schema = self.load_schema_text("""\ """) self.assertRaises(ZConfig.ConfigurationError, self.load_config_text, schema, "") def test_multisection_required(self): schema = self.load_schema_text("""\ """) self.assertRaises(ZConfig.ConfigurationError, self.load_config_text, schema, "") def test_key_required_but_missing(self): schema = self.load_schema_text("""\ """) self.assertRaises(ZConfig.ConfigurationError, self.load_config_text, schema, "") def test_section_required_but_missing(self): schema = self.load_schema_text("""\
""") self.assertRaises(ZConfig.ConfigurationError, self.load_config_text, schema, "") def test_key_default_element(self): self.assertRaises( ZConfig.SchemaError, self.load_schema_text, """\ text """) def test_bad_handler_maps(self): schema = self.load_schema_text("""\ """) conf = self.load_config_text(schema, """\ a foo b bar """, num_handlers=2) self.assertEqual(get_section_attributes(conf), ["a", "b"]) self.assertRaises(ZConfig.ConfigurationError, self.handlers, {'abc': id, 'ABC': id, 'def': id}) self.assertRaises(ZConfig.ConfigurationError, self.handlers, {}) def test_handler_ordering(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, """\ """, num_handlers=3) L = [] self.handlers({'a': L.append, 'b': L.append, 'c': L.append}) outer = conf.sect_outer inner = outer.sect_inner self.assertEqual(L, [inner, outer, conf]) def test_duplicate_section_names(self): schema = self.load_schema_text("""\
""") self.assertRaises(ZConfig.ConfigurationError, self.load_config_text, schema, """\ """) conf = self.load_config_text(schema, """\ """) def test_disallowed_duplicate_attribute(self): self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ """) def test_unknown_datatype_name(self): self.assertRaises(ZConfig.SchemaError, self.load_schema_text, "") def test_load_abstracttype(self): schema = self.load_schema_text("""\ This is an abstract section type. """) # check the types that get defined t = schema.gettype("group") self.assert_(t.isabstract()) t1 = schema.gettype("t1") self.assert_(not t1.isabstract()) self.assert_(t.getsubtype("t1") is t1) t2 = schema.gettype("t2") self.assert_(not t2.isabstract()) self.assert_(t.getsubtype("t2") is t2) self.assertRaises(ZConfig.ConfigurationError, t.getsubtype, "group") self.assert_(t1 is not t2) # try loading a config that relies on this schema conf = self.load_config_text(schema, """\ k1 value1 k2 value2 """) eq = self.assertEqual eq(get_section_attributes(conf), ["g"]) eq(len(conf.g), 4) eq(conf.g[0].k1, "default1") eq(conf.g[1].k1, "value1") eq(conf.g[2].k2, "default2") eq(conf.g[3].k2, "value2") # white box: self.assert_(conf.g[0].getSectionDefinition() is t1) self.assert_(conf.g[1].getSectionDefinition() is t1) self.assert_(conf.g[2].getSectionDefinition() is t2) self.assert_(conf.g[3].getSectionDefinition() is t2) def test_abstracttype_extension(self): schema = self.load_schema_text("""\
""") abstype = schema.gettype("group") self.assert_(schema.gettype("extra") is abstype.getsubtype("extra")) # make sure we can use the extension in a config: conf = self.load_config_text(schema, "") self.assertEqual(conf.thing.getSectionType(), "extra") self.assertEqual(get_section_attributes(conf), ["thing"]) self.assertEqual(get_section_attributes(conf.thing), []) def test_abstracttype_extension_errors(self): # specifying a non-existant abstracttype self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ """) # specifying something that isn't an abstracttype self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ """) def test_arbitrary_key(self): schema = self.load_schema_text("""\ """) conf = self.load_config_text(schema, "some-key 42") self.assertEqual(conf.keymap, {'some-key': 42}) self.assertEqual(get_section_attributes(conf), ["keymap"]) def test_arbitrary_multikey_required(self): schema = self.load_schema_text("""\ """) conf = self.load_config_text(schema, """\ some-key 42 some-key 43 """) self.assertEqual(conf.keymap, {'some-key': [42, 43]}) def test_arbitrary_multikey_optional(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, """\ some-key 42 some-key 43 """) self.assertEqual(conf.stuff.keymap, {'some-key': ['42', '43']}) self.assertEqual(get_section_attributes(conf), ["stuff"]) def test_arbitrary_multikey_optional_empty(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, "") self.assertEqual(conf.stuff.keymap, {}) def test_arbitrary_multikey_with_defaults(self): schema = self.load_schema_text("""\ value-a1 value-a2 value-b """) conf = self.load_config_text(schema, "") self.assertEqual(conf.keymap, {'a': ['value-a1', 'value-a2'], 'b': ['value-b']}) def test_arbitrary_multikey_with_unkeyed_default(self): self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ value-a1 """) def test_arbitrary_key_with_defaults(self): schema = self.load_schema_text("""\ value-a value-b """) conf = self.load_config_text(schema, "") self.assertEqual(conf.keymap, {'a': 'value-a', 'b': 'value-b'}) def test_arbitrary_key_with_unkeyed_default(self): self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ value-a1 """) def test_arbitrary_keys_with_others(self): schema = self.load_schema_text("""\ """) conf = self.load_config_text(schema, """\ some-key 42 k2 3 """) self.assertEqual(conf.k1, 'v1') self.assertEqual(conf.k2, 3) self.assertEqual(conf.keymap, {'some-key': 42}) self.assertEqual(get_section_attributes(conf), ["k1", "k2", "keymap"]) def test_arbitrary_key_missing(self): schema = self.load_schema_text("""\ """) self.assertRaises(ZConfig.ConfigurationError, self.load_config_text, schema, "# empty config file") def test_arbitrary_key_bad_schema(self): self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ """) def test_getrequiredtypes(self): schema = self.load_schema("library.xml") self.assertEqual(schema.getrequiredtypes(), []) schema = self.load_schema_text("""\
""") L = schema.getrequiredtypes() L.sort() self.assertEqual(L, ["used"]) def test_getunusedtypes(self): schema = self.load_schema("library.xml") L = schema.getunusedtypes() L.sort() self.assertEqual(L, ["type-a", "type-b"]) schema = self.load_schema_text("""\
""") self.assertEqual(schema.getunusedtypes(), ["unused"]) def test_section_value_mutation(self): schema, conf = self.load_both("simple.xml", "simple.conf") orig = conf.empty new = [] conf.empty = new self.assert_(conf.empty is new) def test_simple_anonymous_section(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, "") self.assertEqual(conf.attr.key, "value") def test_simple_anonymous_section_without_name(self): # make sure we get the same behavior without name='*' schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, "") self.assertEqual(conf.attr.key, "value") def test_simple_anynamed_section(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, "") self.assertEqual(conf.attr.key, "value") self.assertEqual(conf.attr.getSectionName(), "name") # if we omit the name, it's an error self.assertRaises(ZConfig.ConfigurationError, self.load_config_text, schema, "") def test_nested_abstract_sectiontype(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, """\ """) def test_nested_abstract_sectiontype_without_name(self): # make sure we get the same behavior without name='*' schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, """\ """) def test_reserved_attribute_prefix(self): template = """\ %s """ def check(thing, self=self, template=template): text = template % thing self.assertRaises(ZConfig.SchemaError, self.load_schema_text, text) check("") check("") check("") check("") check("
") check("
") check("") check("") def test_sectiontype_as_schema(self): schema = self.load_schema_text("""\
""") t = schema.gettype("t") conf = self.load_config_text(t, "") self.assertEqual(conf.tkey, "tkey-default") self.assertEqual(conf.section.skey, "skey-default") self.assertEqual(get_section_attributes(conf), ["section", "tkey"]) self.assertEqual(get_section_attributes(conf.section), ["skey"]) def test_datatype_conversion_error(self): schema_url = "file:///tmp/fake-url-1.xml" config_url = "file:///tmp/fake-url-2.xml" schema = self.load_schema_text("""\ """, url=schema_url) e = self.get_data_conversion_error( schema, "", config_url) self.assertEqual(e.url, schema_url) self.assertEqual(e.lineno, 2) e = self.get_data_conversion_error(schema, """\ # comment key splat """, config_url) self.assertEqual(e.url, config_url) self.assertEqual(e.lineno, 3) def get_data_conversion_error(self, schema, src, url): try: self.load_config_text(schema, src, url=url) except ZConfig.DataConversionError, e: return e else: self.fail("expected ZConfig.DataConversionError") def test_numeric_section_name(self): schema = self.load_schema_text("""\ """) conf = self.load_config_text(schema, "") self.assertEqual(len(conf.things), 1) def test_sectiontype_extension(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, """\ k1 k1-value k2 k2-value """) eq = self.assertEqual eq(conf.s.k1, "k1-value") eq(conf.s.k2, "k2-value") eq(get_section_attributes(conf), ["s"]) eq(get_section_attributes(conf.s), ["k1", "k2"]) def test_sectiontype_extension_errors(self): # cannot override key from base self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ """) # cannot extend non-existing section self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ """) # cannot extend abstract type self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ """) def test_sectiontype_derived_keytype(self): # make sure that a derived section type inherits the keytype # of its base schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, """\ foo bar Foo BAR """) self.assertEqual(conf.foo.foo, "bar") self.assertEqual(conf.foo.Foo, "BAR") self.assertEqual(get_section_attributes(conf.foo), ["Foo", "foo"]) def test_sectiontype_override_keytype(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, """\ ident1 foo Ident2 bar EXAMPLE.COM foo """) L = conf.base.map.items() L.sort() self.assertEqual(L, [("Ident2", "bar"), ("ident1", "foo")]) L = conf.derived.map.items() L.sort() self.assertEqual(L, [("example.com", "foo")]) self.assertEqual(get_section_attributes(conf), ["base", "derived"]) def test_keytype_applies_to_default_key(self): schema = self.load_schema_text("""\ 42 24
""") conf = self.load_config_text(schema, "") items = conf.sect.mapping.items() items.sort() self.assertEqual(items, [("bar", "24"), ("foo", "42")]) def test_duplicate_default_key_checked_in_schema(self): self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ 42 24
""") def test_default_keys_rechecked_clash_in_derived_sectiontype(self): # If the default values associated with a can't # be supported by a new keytype for a derived sectiontype, an # error should be indicated. self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ 42 42
""") def test_default_keys_rechecked_dont_clash_in_derived_sectiontype(self): # If the default values associated with a can't # be supported by a new keytype for a derived sectiontype, an # error should be indicated. schema = self.load_schema_text("""\ 42 42
""") conf = self.load_config_text(schema, """\ """) base = conf.base.mapping.items() base.sort() self.assertEqual(base, [("Foo", ["42"]), ("foo", ["42"])]) sect = conf.sect.mapping.items() sect.sort() self.assertEqual(sect, [("foo", ["42", "42"])]) def test_sectiontype_inherited_datatype(self): schema = self.load_schema_text("""\
""") conf = self.load_config_text(schema, """\ foo bar """) self.assertEqual(conf.splat, "bar") def test_schema_keytype(self): schema = self.load_schema_text("""\ """) conf = self.load_config_text(schema, "host.example.com 127.0.0.1\n" "www.example.org 127.0.0.2\n") table = conf.table self.assertEqual(len(table), 2) L = table.items() L.sort() self.assertEqual(L, [("host.example.com", "127.0.0.1"), ("www.example.org", "127.0.0.2")]) self.assertRaises(ZConfig.ConfigurationError, self.load_config_text, schema, "abc. 127.0.0.1") def test_keytype_identifier(self): schema = self.load_schema_text("""\ """) conf = self.load_config_text(schema, "Foo Foo-value\n" "foo foo-value\n") self.assertEqual(conf.foo, "foo-value") self.assertEqual(conf.Foo, "Foo-value") self.assertEqual(get_section_attributes(conf), ["Foo", "foo"]) # key mis-match based on case: self.assertRaises(ZConfig.ConfigurationError, self.load_config_text, schema, "FOO frob\n") # attribute names conflict, since the keytype isn't used to # generate attribute names self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ """) def test_datatype_casesensitivity(self): self.load_schema_text("") def test_simple_extends(self): schema = self.load_schema_text("""\
""" % (CONFIG_BASE, CONFIG_BASE)) self._verifySimpleConf(self.load_config(schema, "simple.conf")) def test_extends_fragment_failure(self): self.assertRaises(ZConfig.SchemaError, self.load_schema_text, "" % CONFIG_BASE) def test_multi_extends_implicit_OK(self): self.load_schema_text("""\
""" % (CONFIG_BASE, CONFIG_BASE)) def test_multi_extends_explicit_datatype_OK(self): self.load_schema_text("""\
""" % (CONFIG_BASE, CONFIG_BASE)) def test_multi_extends_explicit_keytype_OK(self): self.load_schema_text("""\
""" % (CONFIG_BASE, CONFIG_BASE, __name__)) def test_multi_extends_datatype_conflict(self): self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ """ % (CONFIG_BASE, CONFIG_BASE)) def test_multi_extends_keytype_conflict(self): self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ """ % (CONFIG_BASE, CONFIG_BASE)) def test_multiple_descriptions_is_error(self): self.assertRaises(ZConfig.SchemaError, self.load_schema_text, """\ foo bar """) def test_suite(): return unittest.makeSuite(SchemaTestCase) if __name__ == '__main__': unittest.main(defaultTest='test_suite')