package org.incava.doctorj;

import java.io.*;
import java.util.*;
import junit.framework.TestCase;


public class TestItemDocAnalyzer extends Tester
{
    static {
        ItemDocAnalyzer.spellChecker.addDictionary("/usr/share/dict/words");
    }
    
    public TestItemDocAnalyzer(String name)
    {
        super(name);
    }

    // presence of Javadoc

    public void testDocumentedOuterConcreteNonPublicClass()
    {
        evaluate("class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented class", new Integer(1), new Integer(7), new Integer(1), new Integer(10) }
                 });
    }

    public void testDocumentedOuterConcretePublicClass()
    {
        evaluate("public class TestHasJavadoc {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented public class", new Integer(1), new Integer(14), new Integer(1), new Integer(27) }
                 });
    }

    public void testDocumentedOuterAbstractNonPublicClass()
    {
        evaluate("abstract class TestHasJavadoc {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented abstract class", new Integer(1), new Integer(16), new Integer(1), new Integer(29) }
                 });
    }

    public void testDocumentedOuterAbstractPublicClass()
    {
        evaluate("public abstract class TestHasJavadoc {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented public abstract class", new Integer(1), new Integer(23), new Integer(1), new Integer(36) }
                 });
    }

    public void testDocumentedOuterNonPublicInterface()
    {
        evaluate("interface TestHasJavadoc {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented interface", new Integer(1), new Integer(11), new Integer(1), new Integer(24) }
                 });
    }

    public void testDocumentedOuterPublicInterface()
    {
        evaluate("public interface TestHasJavadoc {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented public interface", new Integer(1), new Integer(18), new Integer(1), new Integer(31) }
                 });
    }

    public void testDocumentedInnerConcreteNonPublicClass()
    {
        evaluate("/** this class is commented. */\n" +
                 "class Test {\n" +
                 "    class InnerTestHasJavadoc {\n" +
                 "    }\n" + 
                 "}\n",
                 new Object[][] { 
                     { "Undocumented class", new Integer(3), new Integer(11), new Integer(3), new Integer(29) }
                 });
    }

    public void testDocumentedInnerConcretePublicClass()
    {
        evaluate("/** this class is commented. */\n" +
                 "class Test {\n" +
                 "    public class InnerTestHasJavadoc {\n" +
                 "    }\n" + 
                 "}\n",
                 new Object[][] { 
                     { "Undocumented public class", new Integer(3), new Integer(18), new Integer(3), new Integer(36) }
                 });
    }

    public void testDocumentedInnerAbstractNonPublicClass()
    {
        evaluate("/** this class is commented. */\n" +
                 "class Test {\n" +
                 "    abstract class InnerTestHasJavadoc {\n" +
                 "    }\n" + 
                 "}\n",
                 new Object[][] { 
                     { "Undocumented abstract class", new Integer(3), new Integer(20), new Integer(3), new Integer(38) }
                 });
    }

    public void testDocumentedInnerAbstractPublicClass()
    {
        evaluate("/** this class is commented. */\n" +
                 "class Test {\n" +
                 "    public abstract class InnerTestHasJavadoc {\n" +
                 "    }\n" + 
                 "}\n",
                 new Object[][] { 
                     { "Undocumented public abstract class", new Integer(3), new Integer(27), new Integer(3), new Integer(45) }
                 });
    }

    public void testDocumentedInnerNonPublicInterface()
    {
        evaluate("/** this interface is commented. */\n" +
                 "interface TestHasJavadoc {\n" +
                 "    interface InnerTestHasJavadoc {\n" +
                 "    }\n" + 
                 "}\n",
                 new Object[][] { 
                     { "Undocumented interface", new Integer(3), new Integer(15), new Integer(3), new Integer(33) }
                 });
    }

    public void testDocumentedInnerPublicInterface()
    {
        evaluate("/** this interface is commented. */\n" +
                 "interface TestHasJavadoc {\n" +
                 "    public interface InnerTestHasJavadoc {\n" +
                 "    }\n" + 
                 "}\n",
                 new Object[][] { 
                     { "Undocumented public interface", new Integer(3), new Integer(22), new Integer(3), new Integer(40) }
                 });
    }

    public void testDocumentedNonPublicConstructor()
    {
        evaluate("/** this class is commented. */\n" +
                 "public class TestHasJavadoc {\n" +
                 "    Test() {} \n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented constructor", new Integer(3), new Integer(5), new Integer(3), new Integer(8) }
                 });
    }

    public void testDocumentedPublicConstructor()
    {
        evaluate("/** this class is commented. */\n" +
                 "public class TestHasJavadoc {\n" +
                 "    public TestHasJavadoc() {} \n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented public constructor", new Integer(3), new Integer(12), new Integer(3), new Integer(25) }
                 });
    }

    public void testDocumentedNonPublicMethod()
    {
        evaluate("/** this class is commented. */\n" +
                 "public class TestHasJavadoc {\n" +
                 "    void f() {} \n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented method", new Integer(3), new Integer(10), new Integer(3), new Integer(10) }
                 });
    }

    public void testDocumentedPublicMethod()
    {
        evaluate("/** this class is commented. */\n" +
                 "public class TestHasJavadoc {\n" +
                 "    public void f() {} \n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented public method", new Integer(3), new Integer(17), new Integer(3), new Integer(17) }
                 });
    }

    public void testDocumentedNonPublicField()
    {
        evaluate("/** this class is commented. */\n" +
                 "public class TestHasJavadoc {\n" +
                 "    String s;\n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented field", new Integer(3), new Integer(12), new Integer(3), new Integer(12) }
                 });
    }

    public void testDocumentedPublicField()
    {
        evaluate("/** this class is commented. */\n" +
                 "public class TestHasJavadoc {\n" +
                 "    public String s;\n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented public field", new Integer(3), new Integer(19), new Integer(3), new Integer(19) }
                 });
    }

    public void testDocumentedPublicFieldMultipleVariables()
    {
        evaluate("/** this class is commented. */\n" +
                 "public class TestHasJavadoc {\n" +
                 "    public String s, t, u, v = \"foo\";\n" +
                 "}\n",
                 new Object[][] { 
                     { "Undocumented public field", new Integer(3), new Integer(19), new Integer(3), new Integer(28) }
                 });
    }

    // deprecated
    
    public void testDeprecatedClassWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @deprecated Use something else.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testDeprecatedClassWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @deprecated\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_DEPRECATED_WITHOUT_TEXT, new Integer(2), new Integer(5), new Integer(2), new Integer(15) }
                 });
    }
    
    public void testDeprecatedClassWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  * @deprecated   \n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_DEPRECATED_WITHOUT_TEXT, new Integer(2), new Integer(5), new Integer(2), new Integer(15) }
                 });
    }

    public void testDeprecatedInterfaceWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @deprecated Use something else.\n" +
                 "  */\n" +
                 "interface TestDeprecatedTag {\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testDeprecatedInterfaceWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @deprecated\n" +
                 "  */\n" +
                 "interface TestDeprecatedTag {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_DEPRECATED_WITHOUT_TEXT, new Integer(2), new Integer(5), new Integer(2), new Integer(15) }
                 });
    }
    
    public void testDeprecatedInterfaceWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  * @deprecated   \n" +
                 "  */\n" +
                 "interface TestDeprecatedTag {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_DEPRECATED_WITHOUT_TEXT, new Integer(2), new Integer(5), new Integer(2), new Integer(15) }
                 });
    }

    public void testDeprecatedMethodWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @deprecated Use something else.\n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testDeprecatedMethodWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @deprecated\n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_DEPRECATED_WITHOUT_TEXT, new Integer(5), new Integer(9), new Integer(5), new Integer(19) }
                 });
    }
    
    public void testDeprecatedMethodWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @deprecated    \n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_DEPRECATED_WITHOUT_TEXT, new Integer(5), new Integer(9), new Integer(5), new Integer(19) }
                 });
    }

    public void testDeprecatedFieldWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @deprecated Use something else.\n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testDeprecatedFieldWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @deprecated\n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_DEPRECATED_WITHOUT_TEXT, new Integer(5), new Integer(9), new Integer(5), new Integer(19) }
                 });
    }
    
    public void testDeprecatedFieldWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @deprecated    \n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_DEPRECATED_WITHOUT_TEXT, new Integer(5), new Integer(9), new Integer(5), new Integer(19) }
                 });
    }

    // see

    public void testSeeClassWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @see something else\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description.\n" +
                 "  * @see elsewhere\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testSeeClassWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @see\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SEE_WITHOUT_REFERENCE, new Integer(2), new Integer(5), new Integer(2), new Integer(8) }
                 });
    }
    
    public void testSeeClassWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  * @see   \n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SEE_WITHOUT_REFERENCE, new Integer(2), new Integer(5), new Integer(2), new Integer(8) }
                 });
    }

    public void testSeeInterfaceWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @see something else\n" +
                 "  */\n" +
                 "interface TestSeeTag {\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description.\n" +
                 "  * @see elsewhere\n" +
                 "  */\n" +
                 "interface TestSeeTag {\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testSeeInterfaceWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @see\n" +
                 "  */\n" +
                 "interface TestSeeTag {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SEE_WITHOUT_REFERENCE, new Integer(2), new Integer(5), new Integer(2), new Integer(8) }
                 });
    }
    
    public void testSeeInterfaceWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  * @see   \n" +
                 "  */\n" +
                 "interface TestSeeTag {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SEE_WITHOUT_REFERENCE, new Integer(2), new Integer(5), new Integer(2), new Integer(8) }
                 });
    }

    public void testSeeMethodWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see something else\n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see elsewhere\n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testSeeMethodWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see\n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SEE_WITHOUT_REFERENCE, new Integer(5), new Integer(9), new Integer(5), new Integer(12) }
                 });
    }
    
    public void testSeeMethodWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see    \n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SEE_WITHOUT_REFERENCE, new Integer(5), new Integer(9), new Integer(5), new Integer(12) }
                 });
    }

    public void testSeeFieldWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see something else\n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see elsewhere\n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testSeeFieldWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see\n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SEE_WITHOUT_REFERENCE, new Integer(5), new Integer(9), new Integer(5), new Integer(12) }
                 });
    }
    
    public void testSeeFieldWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see    \n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SEE_WITHOUT_REFERENCE, new Integer(5), new Integer(9), new Integer(5), new Integer(12) }
                 });
    }

    // since

    public void testSinceClassWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @since some version\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description.\n" +
                 "  * @since 3.17\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testSinceClassWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @since\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SINCE_WITHOUT_TEXT, new Integer(2), new Integer(5), new Integer(2), new Integer(10) }
                 });
    }
    
    public void testSinceClassWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  * @since   \n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SINCE_WITHOUT_TEXT, new Integer(2), new Integer(5), new Integer(2), new Integer(10) }
                 });
    }

    public void testSinceInterfaceWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @since some version\n" +
                 "  */\n" +
                 "interface SinceTestTag {\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description.\n" +
                 "  * @since 3.17\n" +
                 "  */\n" +
                 "interface SinceTestTag {\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testSinceInterfaceWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  * @since\n" +
                 "  */\n" +
                 "interface SinceTestTag {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SINCE_WITHOUT_TEXT, new Integer(2), new Integer(5), new Integer(2), new Integer(10) }
                 });
    }
    
    public void testSinceInterfaceWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  * @since   \n" +
                 "  */\n" +
                 "interface SinceTestTag {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SINCE_WITHOUT_TEXT, new Integer(2), new Integer(5), new Integer(2), new Integer(10) }
                 });
    }

    public void testSinceMethodWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @since some version\n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @since 3.17\n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testSinceMethodWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @since\n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SINCE_WITHOUT_TEXT, new Integer(5), new Integer(9), new Integer(5), new Integer(14) }
                 });
    }
    
    public void testSinceMethodWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @since    \n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SINCE_WITHOUT_TEXT, new Integer(5), new Integer(9), new Integer(5), new Integer(14) }
                 });
    }

    public void testSinceFieldWithText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @since some version\n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @since 3.17\n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testSinceFieldWithoutText()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @since\n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SINCE_WITHOUT_TEXT, new Integer(5), new Integer(9), new Integer(5), new Integer(14) }
                 });
    }
    
    public void testSinceFieldWithoutTextSpaces()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @since    \n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SINCE_WITHOUT_TEXT, new Integer(5), new Integer(9), new Integer(5), new Integer(14) }
                 });
    }

    // tag order

    public void testNoTags()
    {
        evaluate("/** This is a description. */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testProperOrder()
    {
        evaluate("/**\n" +
                 "  * This is a description. \n" +
                 "  * @author me \n" +
                 "  * @version 0.1.2 \n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });


        evaluate("/**\n" +
                 "  * This is a description. \n" +
                 "  * @version 0.1.2 \n" +
                 "  * @since 0.1.1 \n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });

        JavadocTags.add(new JavadocTags.TagDescription("@todo", 10, true, true, true, true));
        evaluate("/**\n" +
                 "  * This is a description. \n" +
                 "  * @version 0.1.2 \n" +
                 "  * @since 0.1.1 \n" +
                 "  * @todo fix exception when index < 0 \n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testImproperOrder()
    {
        evaluate("/**\n" +
                 "  * This is a description. \n" +
                 "  * @version 0.1.2 \n" +
                 "  * @author me \n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_TAG_IMPROPER_ORDER, new Integer(4), new Integer(5), new Integer(4), new Integer(11) }
                 });

        evaluate("/**\n" +
                 "  * This is a description. \n" +
                 "  * @since 0.1.2 \n" +
                 "  * @author me \n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_TAG_IMPROPER_ORDER, new Integer(4), new Integer(5), new Integer(4), new Integer(11) }
                 });

        evaluate("/**\n" +
                 "  * This is a description. \n" +
                 "  * @author me \n" +
                 "  * @deprecated stop using this class \n" +
                 "  * @since 0.1.2 \n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_TAG_IMPROPER_ORDER, new Integer(5), new Integer(5), new Integer(5), new Integer(10) }
                 });
    }

    // tag validity

    public void testValidityClassTags()
    {
        evaluate("/** This is a description.\n" +
                 "  * @author me\n" +
                 "  * @version 1.10\n" +
                 "  * @see Spot#run() \n" +
                 "  * @since whenever\n" +
                 "  * @deprecated Use something better than this.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description.\n" +
                 "  * @author me\n" +
                 "  * @version 1.10\n" +
                 "  * @throws NullPointerException Although Java doesn't have pointers.\n" +
                 "  * @see Spot#run() \n" +
                 "  * @since whenever\n" +
                 "  * @deprecated Use something better than this.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Tag not valid for class", new Integer(4), new Integer(5), new Integer(4), new Integer(11) }
                 });
    }

    public void testValidityInnerClassTags()
    {
        evaluate("/** This is a description. */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @author me\n" +
                 "      * @version 1.10\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    class Inner {\n" +
                 "    }\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description. */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @author me\n" +
                 "      * @version 1.10\n" +
                 "      * @throws NullPointerException Although Java doesn't have pointers.\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    class Inner {\n" +
                 "    }\n" +
                 "}\n",
                 new Object[][] { 
                     { "Tag not valid for class", new Integer(6), new Integer(9), new Integer(6), new Integer(15) }
                 });
    }

    public void testValidityInterfaceTags()
    {
        evaluate("/** This is a description.\n" +
                 "  * @author me\n" +
                 "  * @version 1.10\n" +
                 "  * @see Spot#run() \n" +
                 "  * @since whenever\n" +
                 "  * @deprecated Use something better than this.\n" +
                 "  */\n" +
                 "interface TestValidTag {\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description.\n" +
                 "  * @author me\n" +
                 "  * @version 1.10\n" +
                 "  * @throws NullPointerException Impossible because Java doesn't have pointers.\n" +
                 "  * @see Spot#run() \n" +
                 "  * @since whenever\n" +
                 "  * @deprecated Use something better than this.\n" +
                 "  */\n" +
                 "interface TestValidTag {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Tag not valid for interface", new Integer(4), new Integer(5), new Integer(4), new Integer(11) }
                 });
    }

    public void testValidityInnerInterfaceTags()
    {
        evaluate("/** This is a description. */\n" +
                 "interface Outer {\n" +
                 "    /** This is a description.\n" +
                 "      * @author me\n" +
                 "      * @version 1.10\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    interface Inner {\n" +
                 "    }\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description. */\n" +
                 "interface Outer {\n" +
                 "    /** This is a description.\n" +
                 "      * @author me\n" +
                 "      * @version 1.10\n" +
                 "      * @throws NullPointerException Although Java doesn't have pointers.\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    interface Inner {\n" +
                 "    }\n" +
                 "}\n",
                 new Object[][] { 
                     { "Tag not valid for interface", new Integer(6), new Integer(9), new Integer(6), new Integer(15) }
                 });
    }

    public void testValidityMethodTags()
    {
        evaluate("/** This is a description. */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description. */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @author me\n" +
                 "      * @version 1.10\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    void f() {}\n" +
                 "}\n",
                 new Object[][] { 
                     { "Tag not valid for method", new Integer(4), new Integer(9), new Integer(4), new Integer(15) },
                     { "Tag not valid for method", new Integer(5), new Integer(9), new Integer(5), new Integer(16) }
                 });
    }

    public void testValidityCtorTags()
    {
        evaluate("/** This is a description. */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    Test() {}\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description. */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @author me\n" +
                 "      * @version 1.10\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    Test() {}\n" +
                 "}\n",
                 new Object[][] { 
                     { "Tag not valid for constructor", new Integer(4), new Integer(9), new Integer(4), new Integer(15) },
                     { "Tag not valid for constructor", new Integer(5), new Integer(9), new Integer(5), new Integer(16) }
                 });

        evaluate("/** This is a description. */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @author me\n" +
                 "      * @version 1.10\n" +
                 "      * @return Something\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    Test() {}\n" +
                 "}\n",
                 new Object[][] { 
                     { "Tag not valid for constructor", new Integer(4), new Integer(9), new Integer(4), new Integer(15) },
                     { "Tag not valid for constructor", new Integer(5), new Integer(9), new Integer(5), new Integer(16) },
                     { "Tag not valid for constructor", new Integer(6), new Integer(9), new Integer(6), new Integer(15) }
                 });
    }

    public void testValidityFieldTags()
    {
        evaluate("/** This is a description. */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                 });

        evaluate("/** This is a description. */\n" +
                 "class Test {\n" +
                 "    /** This is a description.\n" +
                 "      * @author me\n" +
                 "      * @version 1.10\n" +
                 "      * @see Spot#run() \n" +
                 "      * @since whenever\n" +
                 "      * @deprecated Use something better than this.\n" +
                 "      */\n" +
                 "    int f;\n" +
                 "}\n",
                 new Object[][] { 
                     { "Tag not valid for field", new Integer(4), new Integer(9), new Integer(4), new Integer(15) },
                     { "Tag not valid for field", new Integer(5), new Integer(9), new Integer(5), new Integer(16) }
                 });
    }

    // summary sentence length

    public void testSummarySufficientLength()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }
    
    public void testSummaryNoSummarySentence()
    {
        evaluate("/** \n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_NO_SUMMARY_SENTENCE, new Integer(1), new Integer(1), new Integer(2), new Integer(4) }
                 });
    }
    
    public void testSummaryNoEndingPeriod()
    {
        evaluate("/** \n" +
                 "  * This doesn't have an ending period\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SUMMARY_SENTENCE_DOES_NOT_END_WITH_PERIOD, new Integer(2), new Integer(5), new Integer(2), new Integer(38) }
                 });
    }
    
    public void testSummaryShortSentence()
    {
        evaluate("/** \n" +
                 "  * Too short.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SUMMARY_SENTENCE_TOO_SHORT, new Integer(2), new Integer(5), new Integer(2), new Integer(14) }
                 });

        evaluate("/** \n" +
                 "  * This one too.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SUMMARY_SENTENCE_TOO_SHORT, new Integer(2), new Integer(5), new Integer(2), new Integer(17) }
                 });

        evaluate("/** \n" +
                 "  * This one too. And it has more text that follows,\n" +
                 "  * but should not be marked in the offending sentence.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { ItemDocAnalyzer.MSG_SUMMARY_SENTENCE_TOO_SHORT, new Integer(2), new Integer(5), new Integer(2), new Integer(17) }
                 });
    }

    // spelling

    public void testSpellingOK()
    {
        evaluate("/** This is a description.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                 });
    }

    public void testSpellingOneMistake()
    {
        evaluate("/** This is a descriptino.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Word 'descriptino' appears to be misspelled. Closest matches: description, descriptions, descriptor, descriptive, descriptors", 
                       new Integer(1), new Integer(15), new Integer(1), new Integer(25) }
                 });
    }

    public void testSpellingTwoMistakes()
    {
        evaluate("/** This is an exampel of\n" +
                 "  * badd spelling.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Word 'exampel' appears to be misspelled. Closest matches: example, expel, enamel, exam, examples, expels", 
                       new Integer(1), new Integer(16), new Integer(1), new Integer(22) },
                     { "Word 'badd' appears to be misspelled. Closest matches: bad, bade, bald, band, banded, bard", 
                       new Integer(2), new Integer(5), new Integer(2), new Integer(8) }
                 });
    }

    public void testSpellingEgregiousMistake()
    {
        evaluate("/** This is an egreejish misspelling.\n" +
                 "  */\n" +
                 "class Test {\n" +
                 "}\n",
                 new Object[][] { 
                     { "Word 'egreejish' appears to be misspelled. No close matches", new Integer(1), new Integer(16), new Integer(1), new Integer(24) }
                 });
    }

}
