diff options
author | Markus Keller | 2015-05-26 17:49:54 +0000 |
---|---|---|
committer | Markus Keller | 2015-05-26 17:49:54 +0000 |
commit | 18beb6714e3f702433eb9c54371fa9b57e83555c (patch) | |
tree | d1571049486cac1868cc392ea149698f0d501fee | |
parent | 521f380f74708f1b72e7b9ffabacf5bfbc3b90d0 (diff) | |
download | eclipse.platform.ua-18beb6714e3f702433eb9c54371fa9b57e83555c.tar.gz eclipse.platform.ua-18beb6714e3f702433eb9c54371fa9b57e83555c.tar.xz eclipse.platform.ua-18beb6714e3f702433eb9c54371fa9b57e83555c.zip |
Bug 468364: Add test for generated extension point and API docsI20150526-2010
-rw-r--r-- | org.eclipse.ua.tests.doc/src/org/eclipse/ua/tests/doc/AllTests.java | 10 | ||||
-rw-r--r-- | org.eclipse.ua.tests.doc/src/org/eclipse/ua/tests/doc/internal/linkchecker/ApiDocTest.java | 270 |
2 files changed, 276 insertions, 4 deletions
diff --git a/org.eclipse.ua.tests.doc/src/org/eclipse/ua/tests/doc/AllTests.java b/org.eclipse.ua.tests.doc/src/org/eclipse/ua/tests/doc/AllTests.java index 11d83ef63..6cc2b5a69 100644 --- a/org.eclipse.ua.tests.doc/src/org/eclipse/ua/tests/doc/AllTests.java +++ b/org.eclipse.ua.tests.doc/src/org/eclipse/ua/tests/doc/AllTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 IBM Corporation and others. + * Copyright (c) 2009, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,12 +10,13 @@ *******************************************************************************/ package org.eclipse.ua.tests.doc; -import junit.framework.Test; -import junit.framework.TestSuite; - +import org.eclipse.ua.tests.doc.internal.linkchecker.ApiDocTest; import org.eclipse.ua.tests.doc.internal.linkchecker.PrebuiltIndexChecker; import org.eclipse.ua.tests.doc.internal.linkchecker.TocLinkChecker; +import junit.framework.Test; +import junit.framework.TestSuite; + /* * Tests all user assistance functionality (automated). */ @@ -34,5 +35,6 @@ public class AllTests extends TestSuite { public AllTests() { addTestSuite(PrebuiltIndexChecker.class); addTestSuite(TocLinkChecker.class); + addTestSuite(ApiDocTest.class); } } diff --git a/org.eclipse.ua.tests.doc/src/org/eclipse/ua/tests/doc/internal/linkchecker/ApiDocTest.java b/org.eclipse.ua.tests.doc/src/org/eclipse/ua/tests/doc/internal/linkchecker/ApiDocTest.java new file mode 100644 index 000000000..83a225d88 --- /dev/null +++ b/org.eclipse.ua.tests.doc/src/org/eclipse/ua/tests/doc/internal/linkchecker/ApiDocTest.java @@ -0,0 +1,270 @@ +/******************************************************************************* + * Copyright (c) 2015 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.ua.tests.doc.internal.linkchecker; + +import java.net.URL; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Pattern; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.RegistryFactory; +import org.eclipse.help.IHelpResource; +import org.eclipse.help.IToc; +import org.eclipse.help.IUAElement; +import org.eclipse.help.internal.toc.TocContribution; +import org.eclipse.help.internal.toc.TocFile; +import org.eclipse.help.internal.toc.TocFileParser; +import org.eclipse.osgi.service.resolver.ExportPackageDescription; +import org.eclipse.osgi.service.resolver.PlatformAdmin; +import org.eclipse.osgi.service.resolver.State; +import org.eclipse.ua.tests.doc.internal.Activator; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import junit.framework.TestCase; + +public class ApiDocTest extends TestCase { + + static class InternalExtensionFoundException extends SAXException { + private static final long serialVersionUID = 1L; + } + + static class InternalExtensionFinder extends DefaultHandler { + /* Look for this pattern: + <element name="extension"> + <annotation> + <appInfo> + <meta.element internal="true" /> + */ + + int state = 0; + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + switch (state) { + case 0: + if ("element".equalsIgnoreCase(qName) && "extension".equals(attributes.getValue("name"))) + state = 1; + break; + + case 1: + if ("annotation".equalsIgnoreCase(qName)) + state = 2; + break; + + case 2: + if ("appInfo".equalsIgnoreCase(qName)) + state = 3; + break; + + case 3: + if ("meta.element".equalsIgnoreCase(qName) && "true".equals(attributes.getValue("internal"))) { + throw new InternalExtensionFoundException(); + } + break; + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + state = 0; + } + } + + private static final String[] TOCS = { + "org.eclipse.platform.doc.isv", + "org.eclipse.jdt.doc.isv", + "org.eclipse.pde.doc.user", + }; + private static final String TOPICS_REFERENCE_XML = "topics_Reference.xml"; + private static final String REFERENCE_EXTENSION_POINTS = "reference/extension-points/"; + private static final String REFERENCE_API = "reference/api/"; + private static final Pattern NON_API_PACKAGES = Pattern.compile(".+\\.(?:internal|tests|examples)(?:\\..+)?"); + + /** + * Missing extension points / API packages currently don't make this test fail, + * since the list contains false positives (esp. when run locally). The test doesn't + * know which bundles eventually end up in the build, and which bundles are: + * <ul> + * <li>part of the test infrastructure</li> + * <li>dependencies (e.g. from Orbit)</li> + * <li>unrelated projects in the user's workspace that are not excluded in the launch configuration</li> + * </ul> + * + * However, the test prints potentially missing extension points / API packages to System.out. + * + * @throws Exception + */ + public void testTopicsReference() throws Exception { + System.out.println("Running " + ApiDocTest.class.getName() + "#testTopicsReference()\n"); + + StringBuilder problems = new StringBuilder(); + + Set<String> extIds = new TreeSet<String>(); + Set<String> packageIds = new TreeSet<String>(); + + TocFileParser parser = new TocFileParser(); + for (String tocFile : TOCS) { + TocContribution contribution = parser.parse(new TocFile(tocFile, TOPICS_REFERENCE_XML, true, "en", null, null)); + IToc toc = contribution.getToc(); + IUAElement[] children = toc.getChildren(); + for (IUAElement child : children) { + for (IUAElement child2 : child.getChildren()) { + if (child2 instanceof IHelpResource) { + IHelpResource topic = (IHelpResource) child2; + String href = topic.getHref(); + if (href != null) { + if (href.startsWith(REFERENCE_EXTENSION_POINTS)) { + String id = topic.getLabel(); + if (!extIds.add(id) ) { + problems.append("Extension point label '" + id + "' appears more than once in '" + TOPICS_REFERENCE_XML + "' files.\n"); + continue; + } + String filename = href.substring(REFERENCE_EXTENSION_POINTS.length()); + String expectedFileName = id.replace('.', '_') + ".html"; + if (!expectedFileName.equals(filename)) { + problems.append("File name for extension point '" + id + "' expected: '" + expectedFileName + "' but was: '" + filename + "'\n"); + } + } else if (href.startsWith(REFERENCE_API)) { + String id = topic.getLabel(); + if (!packageIds.add(id) ) { + problems.append("API package label '" + id + "' appears more than once in '" + TOPICS_REFERENCE_XML + "' files.\n"); + continue; + } + String filename = href.substring(REFERENCE_API.length()); + String expectedFileName = id.replace('.', '/') + "/package-summary.html"; + if (!expectedFileName.equals(filename)) { + problems.append("File name for package label '" + id + "' expected: '" + expectedFileName + "' but was: '" + filename + "'\n"); + } + } + } + } + } + } + } + + checkExtensionPoints(extIds, problems); + checkPackages(packageIds, problems); + + assertEquals("", problems.toString()); + } + + protected void checkExtensionPoints(Set<String> extIds, StringBuilder problems) throws Exception { + Set<String> registeredIds = new TreeSet<String>(); + + IExtensionRegistry registry = RegistryFactory.getRegistry(); + IExtensionPoint[] extensionPoints = registry.getExtensionPoints(); + for (IExtensionPoint extensionPoint : extensionPoints) { + String id = extensionPoint.getUniqueIdentifier(); + String schemaReference = extensionPoint.getSchemaReference(); + if (schemaReference == null) { + problems.append("Extension point missing a schema reference: " + id + "\n"); + } else { + String contributor = extensionPoint.getContributor().getName(); + Bundle bundle = Platform.getBundle(contributor); + URL schema = bundle.getEntry(schemaReference); + if (schema == null || schemaReference.isEmpty()) { + System.out.append("Extension point schema file not found for " + id + ": " + schemaReference + "\n"); + continue; + } + + SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + SAXParser parser = parserFactory.newSAXParser(); + InternalExtensionFinder handler = new InternalExtensionFinder(); + try { + parser.parse(schema.toString(), handler); + } catch (InternalExtensionFoundException e) { + continue; // don't report internal extension points + } + } + registeredIds.add(id); + } + + TreeSet<String> unexpectedTocIds = new TreeSet<String>(extIds); + unexpectedTocIds.removeAll(registeredIds); + if (!unexpectedTocIds.isEmpty()) { + problems.append("\n* Unexpected extension points in " + TOPICS_REFERENCE_XML + ":\n"); + for (String unexpectedTocId : unexpectedTocIds) { + problems.append(unexpectedTocId).append('\n'); + } + } + + registeredIds.removeAll(extIds); + if (!registeredIds.isEmpty()) { + // these currently don't make the test fail, since the list contains false positives (esp. when run locally) + System.out.append("\n* Undocumented (non-internal) extension points:\n"); + for (String registeredId : registeredIds) { + System.out.append(registeredId).append('\n'); + } + } + } + + protected void checkPackages(Set<String> packageIds, StringBuilder problems) { + Set<String> exportedPackageIds = new TreeSet<String>(); + + exportedPackageIds.add("org.eclipse.core.runtime.adaptor"); // not exported, but makes sense to document since accessible from outside of OSGi framework + exportedPackageIds.add("org.eclipse.swt.ole.win32"); // somehow missing from State#getExportedPackages(), maybe because it's declared in the fragment only + + BundleContext context = Activator.getDefault().getBundle().getBundleContext(); + ServiceReference<PlatformAdmin> platformAdminReference = context.getServiceReference(PlatformAdmin.class); + PlatformAdmin service = context.getService(platformAdminReference); + State state = service.getState(false); + ExportPackageDescription[] exportedPackages = state.getExportedPackages(); + for (ExportPackageDescription exportPackageDescription : exportedPackages) { + String name = exportPackageDescription.getName(); + if (!NON_API_PACKAGES.matcher(name).matches()) { + if (Boolean.TRUE.equals(exportPackageDescription.getDirective("x-internal")) + || exportPackageDescription.getDirective("x-friends") != null) { + continue; + } + exportedPackageIds.add(name); +// Enumeration<String> packageChildren = exportPackageDescription.getSupplier().getBundle().getEntryPaths(name.replace('.', '/')); +// while (packageChildren != null && packageChildren.hasMoreElements()) { +// String child = packageChildren.nextElement(); +// if (child.endsWith(".class")) { +// exportedPackageIds.add(name); +// break pack; +// } +// } +// System.out.append("Exported package without class files: ").append(name).append('\n'); + } + } + + TreeSet<String> unexpectedPackageIds = new TreeSet<String>(packageIds); + unexpectedPackageIds.removeAll(exportedPackageIds); + if (!unexpectedPackageIds.isEmpty()) { + problems.append("\n* Unexpected exported API packages in " + TOPICS_REFERENCE_XML + ":\n"); + for (String unexpectedTocId : unexpectedPackageIds) { + problems.append(unexpectedTocId).append('\n'); + } + } + + exportedPackageIds.removeAll(packageIds); + if (!exportedPackageIds.isEmpty()) { + // these currently don't make the test fail, since the list contains false positives (esp. when run locally) + System.out.append("\n* Undocumented exported API package:\n"); + for (String exportedPackageId : exportedPackageIds) { + System.out.append(exportedPackageId).append('\n'); + } + } + } + +} |