Merge changes I9f68c887,Ic18f2dc5

* changes:
  Fix data race when ALLOW_MISSING_DEPENDENCIES=true
  Document glob patterns
diff --git a/Android.bp b/Android.bp
index aa65209..4a06a11 100644
--- a/Android.bp
+++ b/Android.bp
@@ -291,6 +291,24 @@
     ],
 }
 
+bootstrap_go_package {
+    name: "soong-xml",
+    pkgPath: "android/soong/xml",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "soong",
+        "soong-android",
+    ],
+    srcs: [
+        "xml/xml.go",
+    ],
+    testSrcs: [
+        "xml/xml_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
+
 //
 // Defaults to enable various configurations of host bionic
 //
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index fee2c49..55a72a6 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -28,45 +28,47 @@
 
 type prebuiltEtcProperties struct {
 	// Source file of this prebuilt.
-	Srcs []string `android:"arch_variant"`
+	Src *string `android:"arch_variant"`
 
 	// optional subdirectory under which this file is installed into
 	Sub_dir *string `android:"arch_variant"`
 }
 
-type prebuiltEtc struct {
+type PrebuiltEtc struct {
 	ModuleBase
-	prebuilt Prebuilt
 
 	properties prebuiltEtcProperties
 
-	sourceFilePath Path
-	installDirPath OutputPath
+	sourceFilePath         Path
+	installDirPath         OutputPath
+	additionalDependencies *Paths
 }
 
-func (p *prebuiltEtc) Prebuilt() *Prebuilt {
-	return &p.prebuilt
-}
-
-func (p *prebuiltEtc) DepsMutator(ctx BottomUpMutatorContext) {
-	if len(p.properties.Srcs) == 0 {
-		ctx.PropertyErrorf("srcs", "missing prebuilt source file")
-	}
-
-	if len(p.properties.Srcs) > 1 {
-		ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+func (p *PrebuiltEtc) DepsMutator(ctx BottomUpMutatorContext) {
+	if p.properties.Src == nil {
+		ctx.PropertyErrorf("src", "missing prebuilt source file")
 	}
 
 	// To support ":modulename" in src
-	ExtractSourceDeps(ctx, &(p.properties.Srcs)[0])
+	ExtractSourceDeps(ctx, p.properties.Src)
 }
 
-func (p *prebuiltEtc) GenerateAndroidBuildActions(ctx ModuleContext) {
-	p.sourceFilePath = ctx.ExpandSource(p.properties.Srcs[0], "srcs")
+func (p *PrebuiltEtc) SourceFilePath(ctx ModuleContext) Path {
+	return ctx.ExpandSource(String(p.properties.Src), "src")
+}
+
+// This allows other derivative modules (e.g. prebuilt_etc_xml) to perform
+// additional steps (like validating the src) before the file is installed.
+func (p *PrebuiltEtc) SetAdditionalDependencies(paths Paths) {
+	p.additionalDependencies = &paths
+}
+
+func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx ModuleContext) {
+	p.sourceFilePath = ctx.ExpandSource(String(p.properties.Src), "src")
 	p.installDirPath = PathForModuleInstall(ctx, "etc", String(p.properties.Sub_dir))
 }
 
-func (p *prebuiltEtc) AndroidMk() AndroidMkData {
+func (p *PrebuiltEtc) AndroidMk() AndroidMkData {
 	return AndroidMkData{
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
 			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
@@ -76,16 +78,26 @@
 			fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
 			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", p.sourceFilePath.String())
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
+			if p.additionalDependencies != nil {
+				fmt.Fprint(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=")
+				for _, path := range *p.additionalDependencies {
+					fmt.Fprint(w, " "+path.String())
+				}
+				fmt.Fprintln(w, "")
+			}
 			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 		},
 	}
 }
 
-func PrebuiltEtcFactory() Module {
-	module := &prebuiltEtc{}
-	module.AddProperties(&module.properties)
+func InitPrebuiltEtcModule(p *PrebuiltEtc) {
+	p.AddProperties(&p.properties)
+}
 
-	InitPrebuiltModule(module, &(module.properties.Srcs))
-	InitAndroidModule(module)
+func PrebuiltEtcFactory() Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module)
+	// This module is device-only
+	InitAndroidArchModule(module, DeviceSupported, MultilibCommon)
 	return module
 }
diff --git a/java/java_test.go b/java/java_test.go
index de514e0..ea52496 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1040,7 +1040,7 @@
 	ctx.ModuleForTests("foo"+sdkDocsSuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkSystemApiSuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkImplLibrarySuffix, "android_common")
-	ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "")
+	ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
 
 	bazJavac := ctx.ModuleForTests("baz", "android_common").Rule("javac")
 	// tests if baz is actually linked to the stubs lib
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 13a9275..45a6a09 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -31,6 +31,7 @@
 var (
 	sdkStubsLibrarySuffix = ".stubs"
 	sdkSystemApiSuffix    = ".system"
+	sdkTestApiSuffix      = ".test"
 	sdkDocsSuffix         = ".docs"
 	sdkImplLibrarySuffix  = ".impl"
 	sdkXmlFileSuffix      = ".xml"
@@ -44,6 +45,15 @@
 var (
 	publicApiStubsTag = dependencyTag{name: "public"}
 	systemApiStubsTag = dependencyTag{name: "system"}
+	testApiStubsTag   = dependencyTag{name: "test"}
+)
+
+type apiScope int
+
+const (
+	apiScopePublic apiScope = iota
+	apiScopeSystem
+	apiScopeTest
 )
 
 var (
@@ -104,12 +114,14 @@
 
 	publicApiStubsPath android.Paths
 	systemApiStubsPath android.Paths
+	testApiStubsPath   android.Paths
 }
 
 func (module *sdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies to the stubs library
-	ctx.AddDependency(ctx.Module(), publicApiStubsTag, module.stubsName(false))
-	ctx.AddDependency(ctx.Module(), systemApiStubsTag, module.stubsName(true))
+	ctx.AddDependency(ctx.Module(), publicApiStubsTag, module.stubsName(apiScopePublic))
+	ctx.AddDependency(ctx.Module(), systemApiStubsTag, module.stubsName(apiScopeSystem))
+	ctx.AddDependency(ctx.Module(), testApiStubsTag, module.stubsName(apiScopeTest))
 }
 
 func (module *sdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -126,6 +138,8 @@
 				module.publicApiStubsPath = stubs.HeaderJars()
 			case systemApiStubsTag:
 				module.systemApiStubsPath = stubs.HeaderJars()
+			case testApiStubsTag:
+				module.testApiStubsPath = stubs.HeaderJars()
 			default:
 				ctx.ModuleErrorf("depends on module %q of unknown tag %q", otherName, tag)
 			}
@@ -148,19 +162,25 @@
 }
 
 // Module name of the stubs library
-func (module *sdkLibrary) stubsName(forSystemApi bool) string {
+func (module *sdkLibrary) stubsName(apiScope apiScope) string {
 	stubsName := module.BaseModuleName() + sdkStubsLibrarySuffix
-	if forSystemApi {
+	switch apiScope {
+	case apiScopeSystem:
 		stubsName = stubsName + sdkSystemApiSuffix
+	case apiScopeTest:
+		stubsName = stubsName + sdkTestApiSuffix
 	}
 	return stubsName
 }
 
 // Module name of the docs
-func (module *sdkLibrary) docsName(forSystemApi bool) string {
+func (module *sdkLibrary) docsName(apiScope apiScope) string {
 	docsName := module.BaseModuleName() + sdkDocsSuffix
-	if forSystemApi {
+	switch apiScope {
+	case apiScopeSystem:
 		docsName = docsName + sdkSystemApiSuffix
+	case apiScopeTest:
+		docsName = docsName + sdkTestApiSuffix
 	}
 	return docsName
 }
@@ -191,10 +211,15 @@
 // SDK version that the stubs library is built against. Note that this is always
 // *current. Older stubs library built with a numberd SDK version is created from
 // the prebuilt jar.
-func (module *sdkLibrary) sdkVersion(forSystemApi bool) string {
-	if forSystemApi {
+func (module *sdkLibrary) sdkVersion(apiScope apiScope) string {
+	switch apiScope {
+	case apiScopePublic:
+		return "current"
+	case apiScopeSystem:
 		return "system_current"
-	} else {
+	case apiScopeTest:
+		return "test_current"
+	default:
 		return "current"
 	}
 }
@@ -202,10 +227,13 @@
 // $(INTERNAL_PLATFORM_<apiTagName>_API_FILE) points to the generated
 // api file for the current source
 // TODO: remove this when apicheck is done in soong
-func (module *sdkLibrary) apiTagName(forSystemApi bool) string {
+func (module *sdkLibrary) apiTagName(apiScope apiScope) string {
 	apiTagName := strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1)
-	if forSystemApi {
+	switch apiScope {
+	case apiScopeSystem:
 		apiTagName = apiTagName + "_SYSTEM"
+	case apiScopeTest:
+		apiTagName = apiTagName + "_TEST"
 	}
 	return apiTagName
 }
@@ -213,11 +241,14 @@
 // returns the path (relative to this module) to the API txt file. Files are located
 // ./<api_dir>/<api_level>.txt where <api_level> is either current, system-current, removed,
 // or system-removed.
-func (module *sdkLibrary) apiFilePath(apiLevel string, forSystemApi bool) string {
+func (module *sdkLibrary) apiFilePath(apiLevel string, apiScope apiScope) string {
 	apiDir := "api"
 	apiFile := apiLevel
-	if forSystemApi {
+	switch apiScope {
+	case apiScopeSystem:
 		apiFile = "system-" + apiFile
+	case apiScopeTest:
+		apiFile = "test-" + apiFile
 	}
 	apiFile = apiFile + ".txt"
 
@@ -225,7 +256,7 @@
 }
 
 // Creates a static java library that has API stubs
-func (module *sdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, forSystemApi bool) {
+func (module *sdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, apiScope apiScope) {
 	props := struct {
 		Name              *string
 		Srcs              []string
@@ -243,10 +274,10 @@
 		}
 	}{}
 
-	props.Name = proptools.StringPtr(module.stubsName(forSystemApi))
+	props.Name = proptools.StringPtr(module.stubsName(apiScope))
 	// sources are generated from the droiddoc
-	props.Srcs = []string{":" + module.docsName(forSystemApi)}
-	props.Sdk_version = proptools.StringPtr(module.sdkVersion(forSystemApi))
+	props.Srcs = []string{":" + module.docsName(apiScope)}
+	props.Sdk_version = proptools.StringPtr(module.sdkVersion(apiScope))
 	// Unbundled apps will use the prebult one from /prebuilts/sdk
 	props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false)
 	props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
@@ -264,7 +295,7 @@
 
 // Creates a droiddoc module that creates stubs source files from the given full source
 // files
-func (module *sdkLibrary) createDocs(mctx android.TopDownMutatorContext, forSystemApi bool) {
+func (module *sdkLibrary) createDocs(mctx android.TopDownMutatorContext, apiScope apiScope) {
 	props := struct {
 		Name                    *string
 		Srcs                    []string
@@ -280,7 +311,7 @@
 		Removed_api_filename    *string
 	}{}
 
-	props.Name = proptools.StringPtr(module.docsName(forSystemApi))
+	props.Name = proptools.StringPtr(module.docsName(apiScope))
 	props.Srcs = module.properties.Srcs
 	props.Custom_template = proptools.StringPtr("droiddoc-templates-sdk")
 	props.Installable = proptools.BoolPtr(false)
@@ -289,8 +320,11 @@
 	droiddocArgs := " -hide 110 -hide 111 -hide 113 -hide 121 -hide 125 -hide 126 -hide 127 -hide 128" +
 		" -stubpackages " + strings.Join(module.properties.Api_packages, ":") +
 		" -nodocs"
-	if forSystemApi {
+	switch apiScope {
+	case apiScopeSystem:
 		droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.SystemApi"
+	case apiScopeTest:
+		droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.TestApi"
 	}
 	props.Args = proptools.StringPtr(droiddocArgs)
 
@@ -300,13 +334,17 @@
 	// TODO: If any incompatible change is detected, break the build
 	currentApiFileName := "current.txt"
 	removedApiFileName := "removed.txt"
-	if forSystemApi {
+	switch apiScope {
+	case apiScopeSystem:
 		currentApiFileName = "system-" + currentApiFileName
 		removedApiFileName = "system-" + removedApiFileName
+	case apiScopeTest:
+		currentApiFileName = "test-" + currentApiFileName
+		removedApiFileName = "test-" + removedApiFileName
 	}
 	currentApiFileName = path.Join("api", currentApiFileName)
 	removedApiFileName = path.Join("api", removedApiFileName)
-	props.Api_tag_name = proptools.StringPtr(module.apiTagName(forSystemApi))
+	props.Api_tag_name = proptools.StringPtr(module.apiTagName(apiScope))
 	// Note: the exact names of these two are not important because they are always
 	// referenced by the make variable $(INTERNAL_PLATFORM_<TAG_NAME>_API_FILE)
 	props.Api_filename = proptools.StringPtr(currentApiFileName)
@@ -407,14 +445,14 @@
 	// <partition>/etc/permissions
 	etcProps := struct {
 		Name             *string
-		Srcs             []string
+		Src              *string
 		Sub_dir          *string
 		Soc_specific     *bool
 		Device_specific  *bool
 		Product_specific *bool
 	}{}
 	etcProps.Name = proptools.StringPtr(module.xmlFileName())
-	etcProps.Srcs = []string{":" + module.xmlFileName() + "-gen"}
+	etcProps.Src = proptools.StringPtr(":" + module.xmlFileName() + "-gen")
 	etcProps.Sub_dir = proptools.StringPtr("permissions")
 	if module.SocSpecific() {
 		etcProps.Soc_specific = proptools.BoolPtr(true)
@@ -448,12 +486,16 @@
 func sdkLibraryMutator(mctx android.TopDownMutatorContext) {
 	if module, ok := mctx.Module().(*sdkLibrary); ok {
 		// for public API stubs
-		module.createStubsLibrary(mctx, false)
-		module.createDocs(mctx, false)
+		module.createStubsLibrary(mctx, apiScopePublic)
+		module.createDocs(mctx, apiScopePublic)
 
 		// for system API stubs
-		module.createStubsLibrary(mctx, true)
-		module.createDocs(mctx, true)
+		module.createStubsLibrary(mctx, apiScopeSystem)
+		module.createDocs(mctx, apiScopeSystem)
+
+		// for test API stubs
+		module.createStubsLibrary(mctx, apiScopeTest)
+		module.createDocs(mctx, apiScopeTest)
 
 		// for runtime
 		module.createXmlFile(mctx)
diff --git a/xml/xml.go b/xml/xml.go
new file mode 100644
index 0000000..218d73c
--- /dev/null
+++ b/xml/xml.go
@@ -0,0 +1,136 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package xml
+
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+// prebuilt_etc_xml installs an xml file under <partition>/etc/<subdir>.
+// It also optionally validates the xml file against the schema.
+
+var (
+	pctx = android.NewPackageContext("android/soong/xml")
+
+	xmllintDtd = pctx.AndroidStaticRule("xmllint-dtd",
+		blueprint.RuleParams{
+			Command:     `$XmlLintCmd --dtdvalid $dtd $in > /dev/null && touch -a $out`,
+			CommandDeps: []string{"$XmlLintCmd"},
+			Restat:      true,
+		},
+		"dtd")
+
+	xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd",
+		blueprint.RuleParams{
+			Command:     `$XmlLintCmd --schema $xsd $in > /dev/null && touch -a $out`,
+			CommandDeps: []string{"$XmlLintCmd"},
+			Restat:      true,
+		},
+		"xsd")
+
+	xmllintMinimal = pctx.AndroidStaticRule("xmllint-minimal",
+		blueprint.RuleParams{
+			Command:     `$XmlLintCmd $in > /dev/null && touch -a $out`,
+			CommandDeps: []string{"$XmlLintCmd"},
+			Restat:      true,
+		})
+)
+
+func init() {
+	android.RegisterModuleType("prebuilt_etc_xml", PrebuiltEtcXmlFactory)
+	pctx.HostBinToolVariable("XmlLintCmd", "xmllint")
+}
+
+type prebuiltEtcXmlProperties struct {
+	// Optional DTD that will be used to validate the xml file.
+	Schema *string
+}
+
+type prebuiltEtcXml struct {
+	android.PrebuiltEtc
+
+	properties prebuiltEtcXmlProperties
+}
+
+func (p *prebuiltEtcXml) timestampFilePath(ctx android.ModuleContext) android.WritablePath {
+	return android.PathForModuleOut(ctx, p.PrebuiltEtc.SourceFilePath(ctx).Base()+"-timestamp")
+}
+
+func (p *prebuiltEtcXml) DepsMutator(ctx android.BottomUpMutatorContext) {
+	p.PrebuiltEtc.DepsMutator(ctx)
+
+	// To support ":modulename" in schema
+	android.ExtractSourceDeps(ctx, p.properties.Schema)
+}
+
+func (p *prebuiltEtcXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	p.PrebuiltEtc.GenerateAndroidBuildActions(ctx)
+
+	if p.properties.Schema != nil {
+		schema := ctx.ExpandSource(proptools.String(p.properties.Schema), "schema")
+
+		switch schema.Ext() {
+		case ".dtd":
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        xmllintDtd,
+				Description: "xmllint-dtd",
+				Input:       p.PrebuiltEtc.SourceFilePath(ctx),
+				Output:      p.timestampFilePath(ctx),
+				Implicit:    schema,
+				Args: map[string]string{
+					"dtd": schema.String(),
+				},
+			})
+			break
+		case ".xsd":
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        xmllintXsd,
+				Description: "xmllint-xsd",
+				Input:       p.PrebuiltEtc.SourceFilePath(ctx),
+				Output:      p.timestampFilePath(ctx),
+				Implicit:    schema,
+				Args: map[string]string{
+					"xsd": schema.String(),
+				},
+			})
+			break
+		default:
+			ctx.PropertyErrorf("schema", "not supported extension: %q", schema.Ext())
+		}
+	} else {
+		// when schema is not specified, just check if the xml is well-formed
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        xmllintMinimal,
+			Description: "xmllint-minimal",
+			Input:       p.PrebuiltEtc.SourceFilePath(ctx),
+			Output:      p.timestampFilePath(ctx),
+		})
+	}
+
+	p.SetAdditionalDependencies([]android.Path{p.timestampFilePath(ctx)})
+}
+
+func PrebuiltEtcXmlFactory() android.Module {
+	module := &prebuiltEtcXml{}
+	module.AddProperties(&module.properties)
+
+	android.InitPrebuiltEtcModule(&module.PrebuiltEtc)
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
diff --git a/xml/xml_test.go b/xml/xml_test.go
new file mode 100644
index 0000000..e8fa49c
--- /dev/null
+++ b/xml/xml_test.go
@@ -0,0 +1,86 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package xml
+
+import (
+	"android/soong/android"
+	"io/ioutil"
+	"os"
+	"testing"
+)
+
+func testXml(t *testing.T, bp string) *android.TestContext {
+	config, buildDir := setup(t)
+	defer teardown(buildDir)
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory))
+	ctx.RegisterModuleType("prebuilt_etc_xml", android.ModuleFactoryAdaptor(PrebuiltEtcXmlFactory))
+	ctx.Register()
+	mockFiles := map[string][]byte{
+		"Android.bp": []byte(bp),
+		"foo.xml":    nil,
+		"foo.dtd":    nil,
+		"bar.xml":    nil,
+		"bar.xsd":    nil,
+	}
+	ctx.MockFileSystem(mockFiles)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	return ctx
+}
+
+func setup(t *testing.T) (config android.Config, buildDir string) {
+	buildDir, err := ioutil.TempDir("", "soong_xml_test")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	config = android.TestArchConfig(buildDir, nil)
+
+	return
+}
+
+func teardown(buildDir string) {
+	os.RemoveAll(buildDir)
+}
+
+// Minimal test
+func TestPrebuiltEtcXml(t *testing.T) {
+	ctx := testXml(t, `
+		prebuilt_etc_xml {
+			name: "foo.xml",
+			src: "foo.xml",
+			schema: "foo.dtd",
+		}
+		prebuilt_etc_xml {
+			name: "bar.xml",
+			src: "bar.xml",
+			schema: "bar.xsd",
+		}
+	`)
+
+	xmllint := ctx.ModuleForTests("foo.xml", "android_common").Rule("xmllint")
+	input := xmllint.Input.String()
+	if input != "foo.xml" {
+		t.Errorf("input expected %q != got %q", "foo.xml", input)
+	}
+	schema := xmllint.Args["dtd"]
+	if schema != "foo.dtd" {
+		t.Errorf("dtd expected %q != got %q", "foo.dtdl", schema)
+	}
+}