001package org.apache.maven.doxia.module;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.IOException;
023import java.io.StringReader;
024import java.io.StringWriter;
025import java.io.Writer;
026
027import org.apache.maven.doxia.AbstractModuleTest;
028
029import org.apache.maven.doxia.logging.PlexusLoggerWrapper;
030import org.apache.maven.doxia.parser.ParseException;
031import org.apache.maven.doxia.parser.Parser;
032
033import org.apache.maven.doxia.sink.Sink;
034import org.apache.maven.doxia.sink.SinkTestDocument;
035import org.apache.maven.doxia.sink.TextSink;
036import org.codehaus.plexus.util.IOUtil;
037
038/**
039 * If a module provides both Parser and Sink, this class
040 * can be used to check that chaining them together
041 * results in the identity transformation, ie the model is still the same
042 * after being piped through a Parser and the corresponding Sink.
043 *
044 * @version $Id$
045 */
046public abstract class AbstractIdentityTest
047    extends AbstractModuleTest
048{
049    /** Expected Identity String */
050    private String expected;
051
052    /**
053     * Set to true if the identity transformation should actually be asserted,
054     * by default only the expected and actual results are written to a file, but not compared.
055     */
056    private boolean assertIdentity;
057
058    /**
059     * Create a new instance of the parser to test.
060     *
061     * @return the parser to test.
062     */
063    protected abstract Parser createParser();
064
065    /**
066     * Return a new instance of the sink that is being tested.
067     *
068     * @param writer The writer for the sink.
069     * @return A new sink.
070     */
071    protected abstract Sink createSink( Writer writer );
072
073    /**
074     * Pipes a full model generated by {@link SinkTestDocument} through
075     * a Sink (generated by {@link #createSink(Writer)}) and a Parser
076     * (generated by {@link #createParser()}) and checks if the result
077     * is the same as the original model. By default, this doesn't actually
078     * assert anything (use {@link #assertIdentity(boolean)} in the setUp()
079     * of an implementation to switch on the test), but the two generated
080     * output files, expected.txt and actual.txt, can be compared for differences.
081     *
082     * @throws IOException if there's a problem reading/writing a test file.
083     * @throws ParseException if a model cannot be parsed.
084     */
085    public void testIdentity()
086        throws IOException, ParseException
087    {
088        // generate the expected model
089        StringWriter writer = new StringWriter();
090        Sink sink = new TextSink( writer );
091        SinkTestDocument.generate( sink );
092        sink.close();
093        expected = writer.toString();
094
095        // write to file for comparison
096        Writer fileWriter = getTestWriter( "expected" );
097        fileWriter.write( expected );
098        IOUtil.close( fileWriter );
099
100        // generate the actual model
101        writer = new StringWriter();
102        sink = createSink( writer );
103        SinkTestDocument.generate( sink );
104        sink.close();
105        StringReader reader = new StringReader( writer.toString() );
106
107        writer = new StringWriter();
108        sink = new TextSink( writer );
109        Parser parser = createParser();
110        parser.enableLogging( new PlexusLoggerWrapper( getContainer().getLogger() ) );
111        parser.parse( reader, sink );
112        String actual = writer.toString();
113
114        // write to file for comparison
115        fileWriter = getTestWriter( "actual" );
116        fileWriter.write( actual );
117        IOUtil.close( fileWriter );
118
119        // Disabled by default, it's unlikely that all our modules
120        // will pass this test any time soon, but the generated
121        // output files can still be compared.
122
123        if ( assertIdentity )
124        {
125            // TODO: make this work for at least apt and xdoc modules?
126            assertEquals( "Identity test failed! See results in " + getTestWriterFile( "actual" ).getParent(),
127                          getExpected(), actual );
128        }
129    }
130
131    /** {@inheritDoc} */
132    protected String getOutputDir()
133    {
134        return "identity/";
135    }
136
137    /**
138     * The output files generated by this class are text files,
139     * independent of the kind of module being tested.
140     *
141     * @return The String "txt".
142     */
143    protected String outputExtension()
144    {
145        return "txt";
146    }
147
148    /**
149     * Set to true if the identity transformation should actually be asserted,
150     * by default only the expected and actual results are written to a file, but not compared.
151     * This should be called during setUp().
152     *
153     * @param doAssert True to actually execute the test.
154     */
155    protected void assertIdentity( boolean doAssert )
156    {
157        this.assertIdentity = doAssert;
158    }
159
160    /**
161     * @return the expected identity string
162     */
163    protected String getExpected()
164    {
165        return expected;
166    }
167}