/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.maven.doxia.sink.impl;

import javax.swing.text.AttributeSet;

import java.util.Enumeration;

import org.apache.maven.doxia.sink.SinkEventAttributes;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

/**
 * Test SinkEventAttributeSet.
 *
 * @author ltheussl
 */
class SinkEventAttributeSetTest {
    private SinkEventAttributeSet sinkEventAttributeSet;

    @BeforeEach
    void setUp() {
        this.sinkEventAttributeSet = new SinkEventAttributeSet();
    }

    /**
     * Test of constructors, of class SinkEventAttributeSet.
     */
    @Test
    void constructor() {
        try {
            new SinkEventAttributeSet("key");
            fail("missing attribute value!");
        } catch (IllegalArgumentException e) {
            assertNotNull(e);
        }
    }

    /**
     * Test of isEmpty method, of class SinkEventAttributeSet.
     */
    @Test
    void isEmpty() {
        assertTrue(sinkEventAttributeSet.isEmpty());
        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.BOLD);
        assertFalse(sinkEventAttributeSet.isEmpty());
    }

    /**
     * Test of getAttributeCount method, of class SinkEventAttributeSet.
     */
    @Test
    void getAttributeCount() {
        assertEquals(0, sinkEventAttributeSet.getAttributeCount());
        sinkEventAttributeSet.addAttribute("name1", "value1");
        assertEquals(1, sinkEventAttributeSet.getAttributeCount());
        sinkEventAttributeSet.removeAttribute("name2");
        assertEquals(1, sinkEventAttributeSet.getAttributeCount());
        sinkEventAttributeSet.removeAttribute("name1");
        assertEquals(0, sinkEventAttributeSet.getAttributeCount());

        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.BOLD);
        assertEquals(1, sinkEventAttributeSet.getAttributeCount());
        sinkEventAttributeSet.removeAttributes(SinkEventAttributeSet.SOURCE);
        assertEquals(1, sinkEventAttributeSet.getAttributeCount());
        sinkEventAttributeSet.removeAttributes(SinkEventAttributeSet.BOLD);
        assertEquals(0, sinkEventAttributeSet.getAttributeCount());
    }

    /**
     * Test of isDefined method, of class SinkEventAttributeSet.
     */
    @Test
    void isDefined() {
        assertFalse(sinkEventAttributeSet.isDefined(SinkEventAttributes.DECORATION));
        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.SOURCE);
        assertTrue(sinkEventAttributeSet.isDefined(SinkEventAttributes.DECORATION));
    }

    /**
     * Test of isEqual method, of class SinkEventAttributeSet.
     */
    @Test
    void isEqual() {
        SinkEventAttributes instance = new SinkEventAttributeSet(SinkEventAttributeSet.BOLD);
        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.BOLD);
        assertTrue(instance.isEqual(sinkEventAttributeSet));
        instance.addAttributes(SinkEventAttributeSet.SOURCE);
        assertFalse(instance.isEqual(sinkEventAttributeSet));
    }

    /**
     * Test of equals method, of class SinkEventAttributeSet.
     */
    @Test
    @SuppressWarnings("SimplifiableJUnitAssertion")
    void equals() {
        assertNotEquals(null, sinkEventAttributeSet);
        //noinspection EqualsWithItself
        assertEquals(sinkEventAttributeSet, sinkEventAttributeSet);

        SinkEventAttributes instance = new SinkEventAttributeSet(SinkEventAttributeSet.BOLD);
        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.BOLD);
        assertEquals(instance, sinkEventAttributeSet);
        instance.addAttributes(SinkEventAttributeSet.SOURCE);
        assertNotEquals(instance, sinkEventAttributeSet);
    }

    /**
     * Test of copyAttributes method, of class SinkEventAttributeSet.
     */
    @Test
    void copyAttributes() {
        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.ITALIC);
        AttributeSet instance = sinkEventAttributeSet.copyAttributes();
        assertTrue(instance.isEqual(sinkEventAttributeSet));
    }

    /**
     * Test of getAttributeNames method, of class SinkEventAttributeSet.
     */
    @Test
    void getAttributeNames() {
        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.UNDERLINE);
        Enumeration<String> result = sinkEventAttributeSet.getAttributeNames();
        assertEquals("decoration", result.nextElement());
        assertFalse(result.hasMoreElements());
    }

    /**
     * Test of getAttribute method, of class SinkEventAttributeSet.
     */
    @Test
    void getAttribute() {
        sinkEventAttributeSet.addAttribute("key", "value");
        assertEquals("value", sinkEventAttributeSet.getAttribute("key"));
        assertNull(sinkEventAttributeSet.getAttribute("bla"));
    }

    /**
     * Test of containsAttribute method, of class SinkEventAttributeSet.
     */
    @Test
    void containsAttribute() {
        sinkEventAttributeSet.addAttribute("key", "value");
        assertTrue(sinkEventAttributeSet.containsAttribute("key", "value"));
        assertFalse(sinkEventAttributeSet.containsAttribute("key", "valu"));
    }

    /**
     * Test of containsAttributes method, of class SinkEventAttributeSet.
     */
    @Test
    void containsAttributes() {
        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.JUSTIFY);
        assertTrue(sinkEventAttributeSet.containsAttributes(SinkEventAttributeSet.JUSTIFY));
        assertFalse(sinkEventAttributeSet.containsAttributes(SinkEventAttributeSet.SOURCE));
    }

    /**
     * Test of addAttribute method, of class SinkEventAttributeSet.
     */
    @Test
    void addAttribute() {
        assertFalse(sinkEventAttributeSet.containsAttribute("key", "value"));
        sinkEventAttributeSet.addAttribute("key", "value");
        assertTrue(sinkEventAttributeSet.containsAttribute("key", "value"));
        sinkEventAttributeSet.removeAttribute("key");
        assertFalse(sinkEventAttributeSet.containsAttribute("key", "value"));
    }

    /**
     * Test of add/removeAttributes methods, of class SinkEventAttributeSet.
     */
    @Test
    void addAttributes() {
        assertFalse(sinkEventAttributeSet.containsAttributes(SinkEventAttributeSet.JUSTIFY));
        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.JUSTIFY);
        assertTrue(sinkEventAttributeSet.containsAttributes(SinkEventAttributeSet.JUSTIFY));

        sinkEventAttributeSet.removeAttributes(SinkEventAttributeSet.JUSTIFY);
        assertFalse(sinkEventAttributeSet.containsAttributes(SinkEventAttributeSet.JUSTIFY));

        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.JUSTIFY);
        sinkEventAttributeSet.removeAttributes(SinkEventAttributeSet.JUSTIFY.getAttributeNames());
        assertFalse(sinkEventAttributeSet.containsAttributes(SinkEventAttributeSet.JUSTIFY));

        sinkEventAttributeSet.setResolveParent(SinkEventAttributeSet.JUSTIFY);
        assertTrue(sinkEventAttributeSet.containsAttributes(SinkEventAttributeSet.JUSTIFY));

        sinkEventAttributeSet.removeAttributes((AttributeSet) null); // should do nothing
    }

    /**
     * Test of getResolveParent method, of class SinkEventAttributeSet.
     */
    @Test
    void getResolveParent() {
        assertNull(sinkEventAttributeSet.getResolveParent());
        sinkEventAttributeSet.setResolveParent(SinkEventAttributeSet.CENTER);
        assertNotNull(sinkEventAttributeSet.getResolveParent());
    }

    /**
     * Test of clone method, of class SinkEventAttributeSet.
     */
    @Test
    void checkClone() {
        Object result = sinkEventAttributeSet.clone();
        assertEquals(sinkEventAttributeSet, result);

        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.MONOSPACED);
        assertNotEquals(sinkEventAttributeSet, result);

        result = sinkEventAttributeSet.clone();
        assertEquals(sinkEventAttributeSet, result);
        sinkEventAttributeSet.setResolveParent(SinkEventAttributeSet.CENTER);
        // assertFalse(sinkEventAttributeSet.equals(result));

        result = sinkEventAttributeSet.clone();
        assertEquals(sinkEventAttributeSet, result);
        sinkEventAttributeSet.setResolveParent(SinkEventAttributeSet.SOURCE);
        // assertFalse(sinkEventAttributeSet.equals(result));
    }

    /**
     * Test of hashCode method, of class SinkEventAttributeSet.
     */
    @Test
    void checkHashCode() {
        int oldValue = sinkEventAttributeSet.hashCode();
        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.BOLD);
        int newValue = sinkEventAttributeSet.hashCode();
        assertNotEquals(oldValue, newValue);

        oldValue = newValue;
        sinkEventAttributeSet.setResolveParent(SinkEventAttributeSet.CENTER);
        newValue = sinkEventAttributeSet.hashCode();
        assertNotEquals(oldValue, newValue);
    }

    /**
     * Test of toString method, of class SinkEventAttributeSet.
     */
    @Test
    void checkToString() {
        String expected = "";
        assertEquals(expected, sinkEventAttributeSet.toString());

        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.SOURCE);
        expected = " decoration=source";
        assertEquals(expected, sinkEventAttributeSet.toString());

        sinkEventAttributeSet.addAttributes(SinkEventAttributeSet.CENTER);
        expected = " decoration=source align=center";
        assertEquals(expected, sinkEventAttributeSet.toString());
    }
}
