package edu.hm.hafner.analysis.parser;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;

import org.apache.commons.io.input.BOMInputStream;

import edu.hm.hafner.analysis.Issue;
import edu.hm.hafner.analysis.IssueBuilder;
import edu.hm.hafner.analysis.Priority;
import edu.hm.hafner.util.Ensure;
import static edu.hm.hafner.analysis.assertj.IssueAssert.*;

/**
 * Base class for parser tests. Provides an assertion test for warnings.
 * <p>
 * FIXME: close files
 */
public abstract class ParserTester {
    public static final String WRONG_NUMBER_OF_WARNINGS_DETECTED = "Wrong number of warnings detected: ";
    public static final String DEFAULT_CATEGORY = new IssueBuilder().build().getCategory();

    /**
     * Checks the properties of the specified warning.
     *
     * @param warning    the warning to check
     * @param lineNumber the expected line number
     * @param message    the expected message
     * @param fileName   the expected filename
     * @param category   the expected category
     * @param priority   the expected priority
     */
    protected void checkWarning(final Issue warning, final int lineNumber, final String message, final String fileName, final String category, final Priority priority) {
        assertThat(warning).hasPriority(priority);
        assertThat(warning).hasCategory(category);
        assertThat(warning).hasLineStart(lineNumber);
        assertThat(warning).hasLineEnd(lineNumber);
        assertThat(warning).hasMessage(message);
        assertThat(warning).hasFileName(fileName);
    }

    /**
     * Checks the properties of the specified warning.
     *
     * @param warning    the warning to check
     * @param lineNumber the expected line number
     * @param column     the expected column
     * @param message    the expected message
     * @param fileName   the expected filename
     * @param category   the expected category
     * @param priority   the expected priority
     */
    protected void checkWarning(final Issue warning, final int lineNumber, final int column, final String message, final String fileName, final String category, final Priority priority) {
        checkWarning(warning, lineNumber, message, fileName, category, priority);
        assertThat(warning).hasColumnStart(column);
    }

    /**
     * Checks the properties of the specified warning.
     *
     * @param warning    the warning to check
     * @param lineNumber the expected line number
     * @param message    the expected message
     * @param fileName   the expected filename
     * @param type       the expected type
     * @param category   the expected category
     * @param priority   the expected priority
     */
    protected void checkWarning(final Issue warning, final int lineNumber, final String message, final String fileName, final String type, final String category, final Priority priority) {
        checkWarning(warning, lineNumber, message, fileName, category, priority);
        assertThat(warning).hasType(type);
    }

    /**
     * Checks the properties of the specified warning.
     *
     * @param warning    the warning to check
     * @param lineNumber the expected line number
     * @param column     the expected column
     * @param message    the expected message
     * @param fileName   the expected filename
     * @param type       the expected type
     * @param category   the expected category
     * @param priority   the expected priority
     */
    protected void checkWarning(final Issue warning, final int lineNumber, final int column, final String message, final String fileName, final String type, final String category, final Priority priority) { // NOCHECKSTYLE
        checkWarning(warning, lineNumber, column, message, fileName, category, priority);
        assertThat(warning).hasType(type);
    }

    /**
     * Returns an input stream with the warnings.
     *
     * @return an input stream
     */
    protected Reader openFile() {
        return openFile(getWarningsFile());
    }

    /**
     * Returns an input stream with the warnings.
     *
     * @param fileName the file to read
     * @return an input stream
     */
    protected Reader openFile(final String fileName) {
        try {
            return new InputStreamReader(new BOMInputStream(asStream(fileName)), "UTF-8");
        }
        catch (UnsupportedEncodingException exception) {
            return new InputStreamReader(asStream(fileName));
        }
    }

    private InputStream asStream(final String fileName) {
        InputStream resourceAsStream = ParserTester.class.getResourceAsStream(fileName);

        Ensure.that(resourceAsStream).isNotNull("File %s not found!", fileName);

        return resourceAsStream;
    }

    /**
     * Returns the file name of the warnings file.
     *
     * @return the warnings file name
     */
    protected abstract String getWarningsFile();
}

@@ -1350,33 +1350,32 @@
 iority(priority)
-;
 %0A        assertT
@@ -1367,35 +1367,24 @@
         
-assertThat(warning)
+        
 .hasCate
@@ -1397,17 +1397,16 @@
 ategory)
-;
 %0A       
@@ -1406,35 +1406,24 @@
         
-assertThat(warning)
+        
 .hasLine
@@ -1431,33 +1431,32 @@
 tart(lineNumber)
-;
 %0A        assertT
@@ -1448,35 +1448,24 @@
         
-assertThat(warning)
+        
 .hasLine
@@ -1479,17 +1479,16 @@
 eNumber)
-;
 %0A       
@@ -1488,35 +1488,24 @@
         
-assertThat(warning)
+        
 .hasMess
@@ -1516,17 +1516,16 @@
 message)
-;
 %0A       
@@ -1525,35 +1525,24 @@
         
-assertThat(warning)
+        
 .hasFile
@@ -2170,109 +2170,263 @@
     
-checkWarning(warning, lineNumber, message, fileName, category, priority);%0A        assertThat(warning)
+assertThat(warning).hasPriority(priority)%0A                .hasCategory(category)%0A                .hasLineStart(lineNumber)%0A                .hasLineEnd(lineNumber)%0A                .hasMessage(message)%0A                .hasFileName(fileName)%0A                
 .has
@@ -3058,109 +3058,263 @@
     
-checkWarning(warning, lineNumber, message, fileName, category, priority);%0A        assertThat(warning)
+assertThat(warning).hasPriority(priority)%0A                .hasCategory(category)%0A                .hasLineStart(lineNumber)%0A                .hasLineEnd(lineNumber)%0A                .hasMessage(message)%0A                .hasFileName(fileName)%0A                
 .has
@@ -4016,117 +4016,303 @@
     
-checkWarning(warning, lineNumber, column, message, fileName, category, priority);%0A        assertThat(warning)
+assertThat(warning).hasPriority(priority)%0A                .hasCategory(category)%0A                .hasLineStart(lineNumber)%0A                .hasLineEnd(lineNumber)%0A                .hasMessage(message)%0A                .hasFileName(fileName)%0A                .hasColumnStart(column)%0A                
 .has

Use fluent API for assertions.