Pārlūkot izejas kodu

XsdDocumentedTests groovy->java

Groovy has more extensive support for Xml parsing via XmlSlurper.
To replace it, this conversion also introduces a SAX wrapper,
NicerXmlParser, and a companion Node wrapper, NicerNode, that
allowed for less modification of the converted tests.

Issue: gh-4939
Josh Cummings 7 gadi atpakaļ
vecāks
revīzija
0c0abea3ad

+ 0 - 33
config/src/test/groovy/org/springframework/security/config/doc/Attribute.groovy

@@ -1,33 +0,0 @@
-/*
- * Copyright 2002-2011 the original author or authors.
- *
- * 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 org.springframework.security.config.doc
-
-/**
- * Represents a Spring Security XSD Attribute. It is created when parsing the current xsd to compare to the documented appendix.
- *
- * @author Rob Winch
- * @see SpringSecurityXsdParser
- * @see XsdDocumentedSpec
- */
-class Attribute {
-	def name
-	def desc
-	def elmt
-
-	def getId() {
-		return "${elmt.id}-${name}".toString()
-	}
-}

+ 0 - 90
config/src/test/groovy/org/springframework/security/config/doc/Element.groovy

@@ -1,90 +0,0 @@
-/*
- * Copyright 2002-2011 the original author or authors.
- *
- * 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 org.springframework.security.config.doc
-
-/**
-* Represents a Spring Security XSD Element. It is created when parsing the current xsd to compare to the documented appendix.
-*
-* @author Rob Winch
-* @see SpringSecurityXsdParser
-* @see XsdDocumentedSpec
-*/
-class Element {
-	def name
-	def desc
-	def attrs
-	/**
-	 * Contains the elements that extend this element (i.e. any-user-service contains ldap-user-service)
-	 */
-	def subGrps = []
-	def childElmts = [:]
-	def parentElmts = [:]
-
-	def getId() {
-		return "nsa-${name}".toString()
-	}
-
-	/**
-	 * Gets all the ids related to this Element including attributes, parent elements, and child elements.
-	 *
-	 * <p>
-	 * The expected ids to be found are documented below.
-	 * <ul>
-	 * <li>Elements - any xml element will have the nsa-&lt;element&gt;. For example the http element will have the id
-	 * nsa-http</li>
-	 * <li>Parent Section - Any element with a parent other than beans will have a section named
-	 * nsa-&lt;element&gt;-parents. For example, authentication-provider would have a section id of
-	 * nsa-authentication-provider-parents. The section would then contain a list of links pointing to the
-	 * documentation for each parent element.</li>
-	 * <li>Attributes Section - Any element with attributes will have a section with the id
-	 * nsa-&lt;element&gt;-attributes. For example the http element would require a section with the id
-	 * http-attributes.</li>
-	 * <li>Attribute - Each attribute of an element would have an id of nsa-&lt;element&gt;-&lt;attributeName&gt;. For
-	 * example the attribute create-session for the http attribute would have the id http-create-session.</li>
-	 * <li>Child Section - Any element with a child element will have a section named nsa-&lt;element&gt;-children.
-	 * For example, authentication-provider would have a section id of nsa-authentication-provider-children. The
-	 * section would then contain a list of links pointing to the documentation for each child element.</li>
-	 * </ul>
-	 * @return
-	 */
-	def getIds() {
-		def ids = [id]
-		childElmts.values()*.ids.each { ids.addAll it }
-		attrs*.id.each { ids.add it }
-		if(childElmts) {
-			ids.add id+'-children'
-		}
-		if(attrs) {
-			ids.add id+'-attributes'
-		}
-		if(parentElmts) {
-			ids.add id+'-parents'
-		}
-		ids
-	}
-
-	def getAllChildElmts() {
-		def result = [:]
-		childElmts.values()*.subGrps*.each { elmt -> result.put(elmt.name,elmt) }
-		result + childElmts
-	}
-
-	def getAllParentElmts() {
-		def result = [:]
-		parentElmts.values()*.subGrps*.each { elmt -> result.put(elmt.name,elmt) }
-		result + parentElmts
-	}
-}

+ 0 - 177
config/src/test/groovy/org/springframework/security/config/doc/SpringSecurityXsdParser.groovy

@@ -1,177 +0,0 @@
-/*
- * Copyright 2002-2011 the original author or authors.
- *
- * 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 org.springframework.security.config.doc
-
-import groovy.xml.Namespace
-
-/**
- * Parses the Spring Security Xsd Document
- *
- * @author Rob Winch
- */
-class SpringSecurityXsdParser {
-	private def rootElement
-
-	private def xs = new Namespace("http://www.w3.org/2001/XMLSchema", 'xs')
-	private def attrElmts = [] as Set
-	private def elementNameToElement = [:] as Map
-
-	/**
-	 * Returns a map of the element name to the {@link Element}.
-	 * @return
-	 */
-	Map<String,Element> parse() {
-		elements(rootElement)
-		elementNameToElement
-	}
-
-	/**
-	 * Creates a Map of the name to an Element object of all the children of element.
-	 *
-	 * @param element
-	 * @return
-	 */
-	private def elements(element) {
-		def elementNameToElement = [:] as Map
-		element.children().each { c->
-			if(c.name() == 'element') {
-			  def e = elmt(c)
-			  elementNameToElement.put(e.name,e)
-			} else {
-			  elementNameToElement.putAll(elements(c))
-			}
-		}
-		elementNameToElement
-	}
-
-	/**
-	 * Any children that are attribute will be returned as an Attribute object.
-	 * @param element
-	 * @return a collection of Attribute objects that are children of element.
-	 */
-	private def attrs(element) {
-		def r = []
-		element.children().each { c->
-			if(c.name() == 'attribute') {
-				r.add(attr(c))
-			}else if(c.name() == 'element') {
-			}else {
-				r.addAll(attrs(c))
-			}
-		}
-		r
-	}
-
-	/**
-	 * Any children will be searched for an attributeGroup, each of it's children will be returned as an Attribute
-	 * @param element
-	 * @return
-	 */
-	private def attrgrps(element) {
-		def r = []
-		element.children().each { c->
-			if(c.name() == 'element') {
-			}else if (c.name() == 'attributeGroup') {
-			   if(c.attributes().get('name')) {
-				   r.addAll(attrgrp(c))
-			   } else {
-				   def n = c.attributes().get('ref').split(':')[1]
-				   def attrGrp = findNode(element,n)
-				   r.addAll(attrgrp(attrGrp))
-			   }
-			} else {
-			   r.addAll(attrgrps(c))
-			}
-		}
-		r
-	}
-
-	private def findNode(c,name) {
-		def root = c
-		while(root.name() != 'schema') {
-			root = root.parent()
-		}
-		def result = root.breadthFirst().find { child-> name == child.@name?.text() }
-		assert result?.@name?.text() == name
-		result
-	}
-
-	/**
-	 * Processes an individual attributeGroup by obtaining all the attributes and then looking for more attributeGroup elements and prcessing them.
-	 * @param e
-	 * @return all the attributes for a specific attributeGroup and any child attributeGroups
-	 */
-	private def attrgrp(e) {
-		def attrs = attrs(e)
-		attrs.addAll(attrgrps(e))
-		attrs
-	}
-
-	/**
-	 * Obtains the description for a specific element
-	 * @param element
-	 * @return
-	 */
-	private def desc(element) {
-		return element['annotation']['documentation']
-	}
-
-	/**
-	 * Given an element creates an attribute from it.
-	 * @param n
-	 * @return
-	 */
-	private def attr(n) {
-		new Attribute(desc: desc(n), name: n.@name.text())
-	}
-
-	/**
-	 * Given an element creates an Element out of it by collecting all its attributes and child elements.
-	 *
-	 * @param n
-	 * @return
-	 */
-	private def elmt(n) {
-		def name = n.@ref.text()
-		if(name) {
-			name = name.split(':')[1]
-			n = findNode(n,name)
-		} else {
-		   name = n.@name.text()
-		}
-		if(elementNameToElement.containsKey(name)) {
-			return elementNameToElement.get(name)
-		}
-		attrElmts.add(name)
-		def e = new Element()
-		e.name = n.@name.text()
-		e.desc = desc(n)
-		e.childElmts = elements(n)
-		e.attrs = attrs(n)
-		e.attrs.addAll(attrgrps(n))
-		e.attrs*.elmt = e
-		e.childElmts.values()*.each { it.parentElmts.put(e.name,e) }
-
-		def subGrpName = n.@substitutionGroup.text()
-		if(subGrpName) {
-			def subGrp = elmt(findNode(n,subGrpName.split(":")[1]))
-			subGrp.subGrps.add(e)
-		}
-
-		elementNameToElement.put(name,e)
-		e
-	}
-}

+ 0 - 222
config/src/test/groovy/org/springframework/security/config/doc/XsdDocumentedTests.groovy

@@ -1,222 +0,0 @@
-/*
- * Copyright 2011-2016 the original author or authors.
- *
- * 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 org.springframework.security.config.doc
-
-import groovy.util.slurpersupport.GPathResult
-import spock.lang.*
-
-import org.springframework.security.config.http.SecurityFilters
-
-/**
- * Tests to ensure that the xsd is properly documented.
- *
- * @author Rob Winch
- */
-class XsdDocumentedTests extends Specification {
-
-	def ignoredIds = [
-		'nsa-any-user-service',
-		'nsa-any-user-service-parents',
-		'nsa-authentication',
-		'nsa-websocket-security',
-		'nsa-ldap',
-		'nsa-method-security',
-		'nsa-web'
-	]
-	@Shared def reference = new File('../docs/manual/src/docs/asciidoc/_includes/appendix/namespace.adoc')
-
-	@Shared File schema31xDocument = new File('src/main/resources/org/springframework/security/config/spring-security-3.1.xsd')
-	@Shared File schemaDocument = new File('src/main/resources/org/springframework/security/config/spring-security-5.0.xsd')
-	@Shared Map<String,Element> elementNameToElement
-	@Shared GPathResult schemaRootElement
-
-	def setupSpec() {
-		schemaRootElement = new XmlSlurper().parse(schemaDocument)
-		elementNameToElement = new SpringSecurityXsdParser(rootElement: schemaRootElement).parse()
-	}
-
-	def cleanupSpec() {
-		reference = null
-		schema31xDocument = null
-		schemaDocument = null
-		elementNameToElement = null
-		schemaRootElement = null
-	}
-
-	def 'SEC-2139: named-security-filter are all defined and ordered properly'() {
-		setup:
-		def expectedFilters = (EnumSet.allOf(SecurityFilters) as List).sort { it.order }
-		when:
-		def nsf = schemaRootElement.simpleType.find { it.@name == 'named-security-filter' }
-		def nsfValues = nsf.children().children().collect { c ->
-			Enum.valueOf(SecurityFilters, c.@value.toString())
-		}
-		then:
-		expectedFilters == nsfValues
-	}
-
-	def 'SEC-2139: 3.1.x named-security-filter are all defined and ordered properly'() {
-		setup:
-		def expectedFilters = [
-			"FIRST",
-			"CHANNEL_FILTER",
-			"SECURITY_CONTEXT_FILTER",
-			"CONCURRENT_SESSION_FILTER",
-			"LOGOUT_FILTER",
-			"X509_FILTER",
-			"PRE_AUTH_FILTER",
-			"CAS_FILTER",
-			"FORM_LOGIN_FILTER",
-			"OPENID_FILTER",
-			"LOGIN_PAGE_FILTER",
-			"DIGEST_AUTH_FILTER",
-			"BASIC_AUTH_FILTER",
-			"REQUEST_CACHE_FILTER",
-			"SERVLET_API_SUPPORT_FILTER",
-			"JAAS_API_SUPPORT_FILTER",
-			"REMEMBER_ME_FILTER",
-			"ANONYMOUS_FILTER",
-			"SESSION_MANAGEMENT_FILTER",
-			"EXCEPTION_TRANSLATION_FILTER",
-			"FILTER_SECURITY_INTERCEPTOR",
-			"SWITCH_USER_FILTER",
-			"LAST"
-		].collect {
-			Enum.valueOf(SecurityFilters, it)
-		}
-		def schema31xRootElement = new XmlSlurper().parse(schema31xDocument)
-		when:
-		def nsf = schema31xRootElement.simpleType.find { it.@name == 'named-security-filter' }
-		def nsfValues = nsf.children().children().collect { c ->
-			Enum.valueOf(SecurityFilters, c.@value.toString())
-		}
-		then:
-		expectedFilters == nsfValues
-	}
-
-	/**
-	 * This will check to ensure that the expected number of xsd documents are found to ensure that we are validating
-	 * against the current xsd document. If this test fails, all that is needed is to update the schemaDocument
-	 * and the expected size for this test.
-	 * @return
-	 */
-	def 'the latest schema is being validated'() {
-		when: 'all the schemas are found'
-		def schemas = schemaDocument.getParentFile().list().findAll { it.endsWith('.xsd') }
-		then: 'the count is equal to 12, if not then schemaDocument needs updated'
-		schemas.size() == 12
-	}
-
-	/**
-	 * This uses a naming convention for the ids of the appendix to ensure that the entire appendix is documented.
-	 * The naming convention for the ids is documented in {@link Element#getIds()}.
-	 * @return
-	 */
-	def 'the entire schema is included in the appendix documentation'() {
-		setup: 'get all the documented ids and the expected ids'
-		def documentedIds = []
-		reference.eachLine { line ->
-			if(line.matches("\\[\\[(nsa-.*)\\]\\]")) {
-				documentedIds.add(line.substring(2,line.length() - 2))
-			}
-		}
-		when: 'the schema is compared to the appendix documentation'
-		def expectedIds = [] as Set
-		elementNameToElement*.value*.ids*.each { expectedIds.addAll it }
-		documentedIds.removeAll ignoredIds
-		expectedIds.removeAll ignoredIds
-		def undocumentedIds = (expectedIds - documentedIds)
-		def shouldNotBeDocumented = (documentedIds - expectedIds)
-		then: 'all the elements and attributes are documented'
-		shouldNotBeDocumented.empty
-		undocumentedIds.empty
-	}
-
-	/**
-	 * This test ensures that any element that has children or parents contains a section that has links pointing to that
-	 * documentation.
-	 * @return
-	 */
-	def 'validate parents and children are linked in the appendix documentation'() {
-		when: "get all the links for each element's children and parents"
-		def docAttrNameToChildren = [:]
-		def docAttrNameToParents = [:]
-
-		def currentDocAttrNameToElmt
-		def docAttrName
-
-		reference.eachLine { line ->
-			if(line.matches('^\\[\\[.*\\]\\]$')) {
-				def id = line.substring(2,line.length() - 2)
-				if(id.endsWith("-children")) {
-					docAttrName = id.substring(0,id.length() - 9)
-					currentDocAttrNameToElmt = docAttrNameToChildren
-				} else if(id.endsWith("-parents")) {
-					docAttrName = id.substring(0,id.length() - 8)
-					currentDocAttrNameToElmt = docAttrNameToParents
-				} else if(docAttrName && !id.startsWith(docAttrName)) {
-					currentDocAttrNameToElmt = null
-					docAttrName = null
-				}
-			}
-
-			if(docAttrName) {
-				def expression = '^\\* <<(nsa-.*),.*>>$'
-				if(line.matches(expression)) {
-					String elmtId = line.replaceAll(expression, '$1')
-					currentDocAttrNameToElmt.get(docAttrName, []).add(elmtId)
-				}
-			}
-		}
-
-		def schemaAttrNameToParents = [:]
-		def schemaAttrNameToChildren = [:]
-		elementNameToElement.each { entry ->
-			def key = 'nsa-'+entry.key
-			if(ignoredIds.contains(key)) {
-				return
-			}
-			def parentIds = entry.value.allParentElmts.values()*.id.findAll { !ignoredIds.contains(it) }.sort()
-			if(parentIds) {
-				schemaAttrNameToParents.put(key,parentIds)
-			}
-			def childIds = entry.value.allChildElmts.values()*.id.findAll { !ignoredIds.contains(it) }.sort()
-			if(childIds) {
-				schemaAttrNameToChildren.put(key,childIds)
-			}
-		}
-		then: "the expected parents and children are all documented"
-		schemaAttrNameToChildren.sort() == docAttrNameToChildren.sort()
-		schemaAttrNameToParents.sort() == docAttrNameToParents.sort()
-	}
-
-	/**
-	 * This test checks each xsd element and ensures there is documentation for it.
-	 * @return
-	 */
-	def 'entire xsd is documented'() {
-		when: "validate that the entire xsd contains documentation"
-		def notDocElmtIds = elementNameToElement.values().findAll {
-			!it.desc.text() && !ignoredIds.contains(it.id)
-		}*.id.sort().join("\n")
-		def notDocAttrIds = elementNameToElement.values()*.attrs.flatten().findAll {
-			!it.desc.text() && !ignoredIds.contains(it.id)
-		}*.id.sort().join("\n")
-		then: "all the elements and attributes have some documentation"
-		!notDocElmtIds
-		!notDocAttrIds
-	}
-}

+ 66 - 0
config/src/test/java/org/springframework/security/config/doc/Attribute.java

@@ -0,0 +1,66 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+/**
+ * Represents a Spring Security XSD Attribute. It is created when parsing the current xsd to compare to the documented appendix.
+ *
+ * @author Rob Winch
+ * @author Josh Cummings
+ *
+ * @see SpringSecurityXsdParser
+ * @see XsdDocumentedTests
+ */
+public class Attribute {
+	private String name;
+
+	private String desc;
+
+	private Element elmt;
+
+	public Attribute(String desc, String name) {
+		this.desc = desc;
+		this.name = name;
+	}
+
+	public String getName() {
+		return this.name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getDesc() {
+		return this.desc;
+	}
+
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+
+	public Element getElmt() {
+		return this.elmt;
+	}
+
+	public void setElmt(Element elmt) {
+		this.elmt = elmt;
+	}
+
+	public String getId() {
+		return String.format("%s-%s", this.elmt.getId(), this.name);
+	}
+}

+ 169 - 0
config/src/test/java/org/springframework/security/config/doc/Element.java

@@ -0,0 +1,169 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a Spring Security XSD Element. It is created when parsing
+ * the current xsd to compare to the documented appendix.
+ *
+ * @author Rob Winch
+ * @author Josh Cummings
+ *
+ * @see SpringSecurityXsdParser
+ * @see XsdDocumentedTests
+*/
+public class Element {
+	private String name;
+	private String desc;
+	private Collection<Attribute> attrs = new ArrayList<>();
+
+	/**
+	 * Contains the elements that extend this element (i.e. any-user-service contains ldap-user-service)
+	 */
+	private Collection<Element> subGrps = new ArrayList<>();
+	private Map<String, Element> childElmts = new HashMap<>();
+	private Map<String, Element> parentElmts = new HashMap<>();
+
+	public String getId() {
+		return String.format("nsa-%s", this.name);
+	}
+
+	public String getName() {
+		return this.name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getDesc() {
+		return this.desc;
+	}
+
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+
+	public Collection<Attribute> getAttrs() {
+		return this.attrs;
+	}
+
+	public void setAttrs(Collection<Attribute> attrs) {
+		this.attrs = attrs;
+	}
+
+	public Collection<Element> getSubGrps() {
+		return this.subGrps;
+	}
+
+	public void setSubGrps(Collection<Element> subGrps) {
+		this.subGrps = subGrps;
+	}
+
+	public Map<String, Element> getChildElmts() {
+		return this.childElmts;
+	}
+
+	public void setChildElmts(Map<String, Element> childElmts) {
+		this.childElmts = childElmts;
+	}
+
+	public Map<String, Element> getParentElmts() {
+		return this.parentElmts;
+	}
+
+	public void setParentElmts(Map<String, Element> parentElmts) {
+		this.parentElmts = parentElmts;
+	}
+
+	/**
+	 * Gets all the ids related to this Element including attributes, parent elements, and child elements.
+	 *
+	 * <p>
+	 * The expected ids to be found are documented below.
+	 * <ul>
+	 * <li>Elements - any xml element will have the nsa-&lt;element&gt;. For example the http element will have the id
+	 * nsa-http</li>
+	 * <li>Parent Section - Any element with a parent other than beans will have a section named
+	 * nsa-&lt;element&gt;-parents. For example, authentication-provider would have a section id of
+	 * nsa-authentication-provider-parents. The section would then contain a list of links pointing to the
+	 * documentation for each parent element.</li>
+	 * <li>Attributes Section - Any element with attributes will have a section with the id
+	 * nsa-&lt;element&gt;-attributes. For example the http element would require a section with the id
+	 * http-attributes.</li>
+	 * <li>Attribute - Each attribute of an element would have an id of nsa-&lt;element&gt;-&lt;attributeName&gt;. For
+	 * example the attribute create-session for the http attribute would have the id http-create-session.</li>
+	 * <li>Child Section - Any element with a child element will have a section named nsa-&lt;element&gt;-children.
+	 * For example, authentication-provider would have a section id of nsa-authentication-provider-children. The
+	 * section would then contain a list of links pointing to the documentation for each child element.</li>
+	 * </ul>
+	 * @return
+	 */
+	public Collection<String> getIds() {
+		Collection<String> ids = new ArrayList<>();
+		ids.add(getId());
+
+		this.childElmts.values()
+			.forEach(elmt -> ids.add(elmt.getId()));
+
+		this.attrs.forEach(attr -> ids.add(attr.getId()));
+
+		if ( !this.childElmts.isEmpty() ) {
+			ids.add(getId() + "-children");
+		}
+
+		if ( !this.attrs.isEmpty() ) {
+			ids.add(getId() + "-attributes");
+		}
+
+		if ( !this.parentElmts.isEmpty() ) {
+			ids.add(getId() + "-parents");
+		}
+
+		return ids;
+	}
+
+	public Map<String, Element> getAllChildElmts() {
+		Map<String, Element> result = new HashMap<>();
+
+		this.childElmts.values()
+			.forEach(elmt ->
+				elmt.subGrps.forEach(
+					subElmt -> result.put(subElmt.name, subElmt)));
+
+		result.putAll(this.childElmts);
+
+		return result;
+	}
+
+	public Map<String, Element> getAllParentElmts() {
+		Map<String, Element> result = new HashMap<>();
+
+		this.parentElmts.values()
+			.forEach(elmt ->
+				elmt.subGrps.forEach(
+					subElmt -> result.put(subElmt.name, subElmt)));
+
+		result.putAll(this.parentElmts);
+
+		return result;
+	}
+}

+ 73 - 0
config/src/test/java/org/springframework/security/config/doc/NicerNode.java

@@ -0,0 +1,73 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.Optional;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+/**
+ * @author Josh Cummings
+ */
+public class NicerNode {
+	private final Node node;
+
+	public NicerNode(Node node) {
+		this.node = node;
+	}
+
+	public String simpleName() {
+		String[] parts = this.node.getNodeName().split(":");
+		return parts[parts.length-1];
+	}
+
+	public String text() {
+		return this.node.getTextContent();
+	}
+
+	public Stream<NicerNode> children() {
+		NodeList children = this.node.getChildNodes();
+
+		return IntStream.range(0, children.getLength())
+				.mapToObj(children::item)
+				.map(NicerNode::new);
+	}
+
+	public Optional<NicerNode> child(String name) {
+		return this.children()
+				.filter(child -> name.equals(child.simpleName()))
+				.findFirst();
+	}
+
+	public Optional<NicerNode> parent() {
+		return Optional.ofNullable(this.node.getParentNode())
+				.map(parent -> new NicerNode(parent));
+	}
+
+	public String attribute(String name) {
+		return Optional.ofNullable(this.node.getAttributes())
+				.map(attrs -> attrs.getNamedItem(name))
+				.map(attr -> attr.getTextContent())
+				.orElse(null);
+	}
+
+	public Node node() {
+		return this.node;
+	}
+}

+ 51 - 0
config/src/test/java/org/springframework/security/config/doc/NicerXmlParser.java

@@ -0,0 +1,51 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author Josh Cummings
+ */
+public class NicerXmlParser implements AutoCloseable {
+	private InputStream xml;
+
+	public NicerXmlParser(InputStream xml) {
+		this.xml = xml;
+	}
+
+	public NicerNode parse() {
+		try {
+			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+
+			return new NicerNode(dBuilder.parse(this.xml));
+		} catch ( IOException | ParserConfigurationException | SAXException e ) {
+			throw new IllegalStateException(e);
+		}
+	}
+
+	@Override
+	public void close() throws IOException {
+		this.xml.close();
+	}
+}

+ 48 - 0
config/src/test/java/org/springframework/security/config/doc/NicerXmlSupport.java

@@ -0,0 +1,48 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Support for ensuring preparing the givens in {@link XsdDocumentedTests}
+ *
+ * @author Josh Cummings
+ */
+public class NicerXmlSupport {
+	private NicerXmlParser parser;
+
+	public NicerNode parse(String location) throws IOException {
+		ClassPathResource resource = new ClassPathResource(location);
+		this.parser = new NicerXmlParser(resource.getInputStream());
+
+		return this.parser.parse();
+	}
+
+	public Map<String, Element> elementsByElementName(String location) throws IOException {
+		NicerNode node = parse(location);
+		return new SpringSecurityXsdParser(node).parse();
+	}
+
+	public void close() throws IOException {
+		if ( this.parser != null ) {
+			this.parser.close();
+		}
+	}
+}

+ 211 - 0
config/src/test/java/org/springframework/security/config/doc/SpringSecurityXsdParser.java

@@ -0,0 +1,211 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import org.springframework.util.StringUtils;
+
+import java.util.*;
+import java.util.stream.Stream;
+
+/**
+ * Parses the Spring Security Xsd Document
+ *
+ * @author Rob Winch
+ * @author Josh Cummings
+ */
+public class SpringSecurityXsdParser {
+	private NicerNode rootElement;
+
+	private Set<String> attrElmts = new LinkedHashSet<>();
+	private Map<String, Element> elementNameToElement = new HashMap<>();
+
+	public SpringSecurityXsdParser(NicerNode rootElement) {
+		this.rootElement = rootElement;
+	}
+
+	/**
+	 * Returns a map of the element name to the {@link Element}.
+	 *
+	 * @return
+	 */
+	public Map<String, Element> parse() {
+		elements(this.rootElement);
+		return this.elementNameToElement;
+	}
+
+	/**
+	 * Creates a Map of the name to an Element object of all the children of element.
+	 *
+	 * @param node
+	 * @return
+	 */
+	private Map<String, Element> elements(NicerNode node) {
+		Map<String, Element> elementNameToElement = new HashMap<>();
+
+		node.children().forEach(child -> {
+			if ("element".equals(child.simpleName())) {
+				Element e = elmt(child);
+				elementNameToElement.put(e.getName(), e);
+			} else {
+				elementNameToElement.putAll(elements(child));
+			}
+		});
+
+		return elementNameToElement;
+	}
+
+	/**
+	 * Any children that are attribute will be returned as an Attribute object.
+	 *
+	 * @param element
+	 * @return a collection of Attribute objects that are children of element.
+	 */
+	private Collection<Attribute> attrs(NicerNode element) {
+		Collection<Attribute> attrs = new ArrayList<>();
+		element.children().forEach(c -> {
+			String name = c.simpleName();
+			if ("attribute".equals(name)) {
+				attrs.add(attr(c));
+			} else if ("element".equals(name)) {
+			} else {
+				attrs.addAll(attrs(c));
+			}
+		});
+
+		return attrs;
+	}
+
+	/**
+	 * Any children will be searched for an attributeGroup, each of its children will be returned as an Attribute
+	 *
+	 * @param element
+	 * @return
+	 */
+	private Collection<Attribute> attrgrps(NicerNode element) {
+		Collection<Attribute> attrgrp = new ArrayList<>();
+
+		element.children().forEach(c -> {
+			if ("element".equals(c.simpleName())) {
+
+			} else if ("attributeGroup".equals(c.simpleName())) {
+				if (c.attribute("name") != null) {
+					attrgrp.addAll(attrgrp(c));
+				} else {
+					String name = c.attribute("ref").split(":")[1];
+					NicerNode attrGrp = findNode(element, name);
+					attrgrp.addAll(attrgrp(attrGrp));
+				}
+			} else {
+				attrgrp.addAll(attrgrps(c));
+			}
+		});
+
+		return attrgrp;
+	}
+
+	private NicerNode findNode(NicerNode c, String name) {
+		NicerNode root = c;
+		while (!"schema".equals(root.simpleName())) {
+			root = root.parent().get();
+		}
+
+		return expand(root)
+				.filter(node -> name.equals(node.attribute("name")))
+				.findFirst().orElseThrow(IllegalArgumentException::new);
+	}
+
+	private Stream<NicerNode> expand(NicerNode root) {
+		return Stream.concat(
+				Stream.of(root),
+				root.children().flatMap(this::expand));
+	}
+
+	/**
+	 * Processes an individual attributeGroup by obtaining all the attributes and then looking for more attributeGroup elements and prcessing them.
+	 *
+	 * @param e
+	 * @return all the attributes for a specific attributeGroup and any child attributeGroups
+	 */
+	private Collection<Attribute> attrgrp(NicerNode e) {
+		Collection<Attribute> attrs = attrs(e);
+		attrs.addAll(attrgrps(e));
+		return attrs;
+	}
+
+	/**
+	 * Obtains the description for a specific element
+	 *
+	 * @param element
+	 * @return
+	 */
+	private String desc(NicerNode element) {
+		return element.child("annotation")
+				.flatMap(annotation -> annotation.child("documentation"))
+				.map(documentation -> documentation.text())
+				.orElse(null);
+	}
+
+	/**
+	 * Given an element creates an attribute from it.
+	 *
+	 * @param n
+	 * @return
+	 */
+	private Attribute attr(NicerNode n) {
+		return new Attribute(desc(n), n.attribute("name"));
+	}
+
+	/**
+	 * Given an element creates an Element out of it by collecting all its attributes and child elements.
+	 *
+	 * @param n
+	 * @return
+	 */
+	private Element elmt(NicerNode n) {
+		String name = n.attribute("ref");
+		if (StringUtils.isEmpty(name)) {
+			name = n.attribute("name");
+		} else {
+			name = name.split(":")[1];
+			n = findNode(n, name);
+		}
+
+		if (this.elementNameToElement.containsKey(name)) {
+			return this.elementNameToElement.get(name);
+		}
+		this.attrElmts.add(name);
+
+		Element e = new Element();
+		e.setName(n.attribute("name"));
+		e.setDesc(desc(n));
+		e.setChildElmts(elements(n));
+		e.setAttrs(attrs(n));
+		e.getAttrs().addAll(attrgrps(n));
+		e.getAttrs().forEach(attr -> attr.setElmt(e));
+		e.getChildElmts().values().forEach(element ->
+				element.getParentElmts().put(e.getName(), e));
+
+		String subGrpName = n.attribute("substitutionGroup");
+		if (!StringUtils.isEmpty(subGrpName)) {
+			Element subGrp = elmt(findNode(n, subGrpName.split(":")[1]));
+			subGrp.getSubGrps().add(e);
+		}
+
+		this.elementNameToElement.put(name, e);
+
+		return e;
+	}
+}

+ 293 - 0
config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java

@@ -0,0 +1,293 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import org.apache.commons.lang.StringUtils;
+import org.junit.After;
+import org.junit.Test;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.security.config.http.SecurityFiltersAssertions;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests to ensure that the xsd is properly documented.
+ *
+ * @author Rob Winch
+ * @author Josh Cummings
+ */
+public class XsdDocumentedTests {
+
+	Collection<String> ignoredIds = Arrays.asList(
+		"nsa-any-user-service",
+		"nsa-any-user-service-parents",
+		"nsa-authentication",
+		"nsa-websocket-security",
+		"nsa-ldap",
+		"nsa-method-security",
+		"nsa-web");
+
+	String referenceLocation = "../docs/manual/src/docs/asciidoc/_includes/appendix/namespace.adoc";
+
+	String schema31xDocumentLocation = "org/springframework/security/config/spring-security-3.1.xsd";
+	String schemaDocumentLocation = "org/springframework/security/config/spring-security-5.0.xsd";
+
+	NicerXmlSupport xml = new NicerXmlSupport();
+
+	@After
+	public void close() throws IOException {
+		this.xml.close();
+	}
+
+	@Test
+	public void parseWhenLatestXsdThenAllNamedSecurityFiltersAreDefinedAndOrderedProperly()
+		throws IOException {
+		NicerNode root = this.xml.parse(this.schemaDocumentLocation);
+
+		List<String> nodes =
+			root.child("schema")
+				.map(NicerNode::children)
+				.orElse(Stream.empty())
+				.filter(node ->
+					"simpleType".equals(node.simpleName()) &&
+					"named-security-filter".equals(node.attribute("name")))
+				.flatMap(NicerNode::children)
+				.flatMap(NicerNode::children)
+				.map(node -> node.attribute("value"))
+				.filter(StringUtils::isNotEmpty)
+				.collect(Collectors.toList());
+
+		SecurityFiltersAssertions.assertEquals(nodes);
+	}
+
+	@Test
+	public void parseWhen31XsdThenAllNamedSecurityFiltersAreDefinedAndOrderedProperly()
+		throws IOException {
+
+		List<String> expected = Arrays.asList(
+			"FIRST",
+			"CHANNEL_FILTER",
+			"SECURITY_CONTEXT_FILTER",
+			"CONCURRENT_SESSION_FILTER",
+			"LOGOUT_FILTER",
+			"X509_FILTER",
+			"PRE_AUTH_FILTER",
+			"CAS_FILTER",
+			"FORM_LOGIN_FILTER",
+			"OPENID_FILTER",
+			"LOGIN_PAGE_FILTER",
+			"DIGEST_AUTH_FILTER",
+			"BASIC_AUTH_FILTER",
+			"REQUEST_CACHE_FILTER",
+			"SERVLET_API_SUPPORT_FILTER",
+			"JAAS_API_SUPPORT_FILTER",
+			"REMEMBER_ME_FILTER",
+			"ANONYMOUS_FILTER",
+			"SESSION_MANAGEMENT_FILTER",
+			"EXCEPTION_TRANSLATION_FILTER",
+			"FILTER_SECURITY_INTERCEPTOR",
+			"SWITCH_USER_FILTER",
+			"LAST"
+		);
+
+		NicerNode root = this.xml.parse(this.schema31xDocumentLocation);
+
+		List<String> nodes =
+			root.child("schema")
+				.map(NicerNode::children)
+				.orElse(Stream.empty())
+				.filter(node ->
+					"simpleType".equals(node.simpleName()) &&
+						"named-security-filter".equals(node.attribute("name")))
+				.flatMap(NicerNode::children)
+				.flatMap(NicerNode::children)
+				.map(node -> node.attribute("value"))
+				.filter(StringUtils::isNotEmpty)
+				.collect(Collectors.toList());
+
+		assertThat(nodes).isEqualTo(expected);
+	}
+
+	/**
+	 * This will check to ensure that the expected number of xsd documents are found to ensure that we are validating
+	 * against the current xsd document. If this test fails, all that is needed is to update the schemaDocument
+	 * and the expected size for this test.
+	 * @return
+	 */
+	@Test
+	public void sizeWhenReadingFilesystemThenIsCorrectNumberOfSchemaFiles()
+		throws IOException {
+
+		ClassPathResource resource = new ClassPathResource(this.schemaDocumentLocation);
+
+		String[] schemas = resource.getFile().getParentFile().list((dir, name) -> name.endsWith(".xsd"));
+
+		assertThat(schemas.length).isEqualTo(12)
+			.withFailMessage("the count is equal to 12, if not then schemaDocument needs updating");
+	}
+
+	/**
+	 * This uses a naming convention for the ids of the appendix to ensure that the entire appendix is documented.
+	 * The naming convention for the ids is documented in {@link Element#getIds()}.
+	 * @return
+	 */
+	@Test
+	public void countReferencesWhenReviewingDocumentationThenEntireSchemaIsIncluded()
+		throws IOException {
+
+		Map<String, Element> elementsByElementName =
+			this.xml.elementsByElementName(this.schemaDocumentLocation);
+
+		List<String> documentIds =
+			Files.lines(Paths.get(this.referenceLocation))
+				.filter(line -> line.matches("\\[\\[(nsa-.*)\\]\\]"))
+				.map(line -> line.substring(2, line.length() - 2))
+				.collect(Collectors.toList());
+
+		Set<String> expectedIds =
+			elementsByElementName.values().stream()
+				.flatMap(element -> element.getIds().stream())
+				.collect(Collectors.toSet());
+
+		documentIds.removeAll(this.ignoredIds);
+		expectedIds.removeAll(this.ignoredIds);
+
+		assertThat(documentIds).containsAll(expectedIds);
+		assertThat(expectedIds).containsAll(documentIds);
+	}
+
+	/**
+	 * This test ensures that any element that has children or parents contains a section that has links pointing to that
+	 * documentation.
+	 * @return
+	 */
+	@Test
+	public void countLinksWhenReviewingDocumentationThenParentsAndChildrenAreCorrectlyLinked()
+		throws IOException {
+
+		Map<String, List<String>> docAttrNameToChildren = new HashMap<>();
+		Map<String, List<String>> docAttrNameToParents = new HashMap<>();
+
+		String docAttrName = null;
+		Map<String, List<String>> currentDocAttrNameToElmt = null;
+
+		List<String> lines = Files.readAllLines(Paths.get(this.referenceLocation));
+		for ( String line : lines ) {
+			if(line.matches("^\\[\\[.*\\]\\]$")) {
+				String id = line.substring(2, line.length() - 2);
+
+				if(id.endsWith("-children")) {
+					docAttrName = id.substring(0, id.length() - 9);
+					currentDocAttrNameToElmt = docAttrNameToChildren;
+				} else if(id.endsWith("-parents")) {
+					docAttrName = id.substring(0, id.length() - 8);
+					currentDocAttrNameToElmt = docAttrNameToParents;
+				} else if(docAttrName != null && !id.startsWith(docAttrName)) {
+					currentDocAttrNameToElmt = null;
+					docAttrName = null;
+				}
+			}
+
+			if(docAttrName != null && currentDocAttrNameToElmt != null) {
+				String expression = "^\\* <<(nsa-.*),.*>>$";
+				if(line.matches(expression)) {
+					String elmtId = line.replaceAll(expression, "$1");
+					currentDocAttrNameToElmt
+							.computeIfAbsent(docAttrName, key -> new ArrayList<>())
+							.add(elmtId);
+				}
+			}
+		}
+
+		Map<String, Element> elementNameToElement = this.xml.elementsByElementName(this.schemaDocumentLocation);
+
+		Map<String, List<String>> schemaAttrNameToChildren = new HashMap<>();
+		Map<String, List<String>> schemaAttrNameToParents = new HashMap<>();
+
+		elementNameToElement.entrySet().stream()
+			.forEach(entry -> {
+				String key = "nsa-" + entry.getKey();
+				if (this.ignoredIds.contains(key) ) {
+					return;
+				}
+
+				List<String> parentIds =
+					entry.getValue().getAllParentElmts().values().stream()
+							.filter(element -> !this.ignoredIds.contains(element.getId()))
+							.map(element -> element.getId())
+							.sorted()
+							.collect(Collectors.toList());
+				if ( !parentIds.isEmpty() ) {
+					schemaAttrNameToParents.put(key, parentIds);
+				}
+
+				List<String> childIds =
+					entry.getValue().getAllChildElmts().values().stream()
+							.filter(element -> !this.ignoredIds.contains(element.getId()))
+							.map(element -> element.getId())
+							.sorted()
+							.collect(Collectors.toList());
+				if ( !childIds.isEmpty() ) {
+					schemaAttrNameToChildren.put(key, childIds);
+				}
+			});
+
+		assertThat(docAttrNameToChildren).isEqualTo(schemaAttrNameToChildren);
+		assertThat(docAttrNameToParents).isEqualTo(schemaAttrNameToParents);
+	}
+
+
+	/**
+	 * This test checks each xsd element and ensures there is documentation for it.
+	 * @return
+	 */
+	@Test
+	public void countWhenReviewingDocumentationThenAllElementsDocumented()
+		throws IOException {
+
+		Map<String, Element> elementNameToElement =
+				this.xml.elementsByElementName(this.schemaDocumentLocation);
+
+		String notDocElmtIds =
+				elementNameToElement.values().stream()
+						.filter(element ->
+								StringUtils.isEmpty(element.getDesc()) &&
+								!this.ignoredIds.contains(element.getId()))
+						.map(element -> element.getId())
+						.sorted()
+						.collect(Collectors.joining("\n"));
+
+		String notDocAttrIds =
+				elementNameToElement.values().stream()
+						.flatMap(element -> element.getAttrs().stream())
+						.filter(element ->
+								StringUtils.isEmpty(element.getDesc()) &&
+										!this.ignoredIds.contains(element.getId()))
+						.map(element -> element.getId())
+						.sorted()
+						.collect(Collectors.joining("\n"));
+
+		assertThat(notDocElmtIds).isEmpty();
+		assertThat(notDocAttrIds).isEmpty();
+	}
+}

+ 40 - 0
config/src/test/java/org/springframework/security/config/http/SecurityFiltersAssertions.java

@@ -0,0 +1,40 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.http;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Assertions for tests that rely on confirming behavior of the package-private SecurityFilters enum
+ *
+ * @author Josh Cummings
+ */
+public class SecurityFiltersAssertions {
+	private static Collection<SecurityFilters> ordered = Arrays.asList(SecurityFilters.values());
+
+	public static void assertEquals(List<String> filters) {
+		List<String> expected = ordered.stream()
+				.map(SecurityFilters::name)
+				.collect(Collectors.toList());
+
+		assertThat(filters).isEqualTo(expected);
+	}
+}