/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.sdm.domain.service.impl;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import javax.json.JsonObject;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Path;

import com.scytl.products.ov.commons.path.PathResolver;
import com.scytl.products.ov.sdm.domain.model.electionevent.ElectionEventRepository;
import com.scytl.products.ov.sdm.domain.model.generator.DataGeneratorResponse;
import com.scytl.products.ov.sdm.infrastructure.JsonConstants;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;

/**
 * The JUnit for {@link EncryptionParametersDataGeneratorServiceImpl}.
 */
@RunWith(MockitoJUnitRunner.class)
public class EncryptionParametersDataGeneratorServiceImplTest {

	private String electionEventId = null;

	@InjectMocks
	@Spy
	private EncryptionParametersDataGeneratorServiceImpl encryptionParametersDataGeneratorService;

	@Mock
	private PathResolver pathResolverMock;

	@Mock
	private Path configPathMock;

	@Mock
	private ElectionEventRepository electionEventRepositoryMock;

	@Mock
	private JsonObject jsonObjectMock;

	@Mock
	private OutputStream outputStreamMock;

	@Test
	public void generateWithIdNull() {
		DataGeneratorResponse result = encryptionParametersDataGeneratorService.generate(electionEventId);

		assertFalse(result.isSuccessful());
	}

	@Test
	public void generateWithIdEmpty() {
		electionEventId = "";
		DataGeneratorResponse result = encryptionParametersDataGeneratorService.generate(electionEventId);

		assertFalse(result.isSuccessful());
	}

	@Test
	public void generateThrowIOExceptionFromCreateDir() throws IOException {
		electionEventId = "12345";

		when(configPathMock.resolve(anyString())).thenReturn(configPathMock);
		when(pathResolverMock.resolve(anyString())).thenReturn(configPathMock);
		doThrow(new IOException()).when(encryptionParametersDataGeneratorService).makePath(configPathMock);

		DataGeneratorResponse result = encryptionParametersDataGeneratorService.generate(electionEventId);
		assertFalse(result.isSuccessful());
	}

	@Test
	public void generateElectionEventNotFound() throws IOException {
		electionEventId = "12345";

		when(configPathMock.resolve(anyString())).thenReturn(configPathMock);
		when(pathResolverMock.resolve(anyString())).thenReturn(configPathMock);
		when(electionEventRepositoryMock.find(electionEventId)).thenReturn(JsonConstants.JSON_EMPTY_OBJECT);

		doReturn(configPathMock).when(encryptionParametersDataGeneratorService).makePath(configPathMock);

		DataGeneratorResponse result = encryptionParametersDataGeneratorService.generate(electionEventId);
		assertFalse(result.isSuccessful());
	}

	@Test
	public void generateThrowIOExceptionFromCreateFile() throws IOException {
		electionEventId = "12345";
		String electionEvent = "";

		when(configPathMock.resolve(anyString())).thenReturn(configPathMock);
		when(pathResolverMock.resolve(anyString())).thenReturn(configPathMock);
		when(jsonObjectMock.getJsonObject(anyString())).thenReturn(jsonObjectMock);
		when(jsonObjectMock.getJsonObject(anyString())).thenReturn(jsonObjectMock);
		when(electionEventRepositoryMock.find(electionEventId)).thenReturn(electionEvent);

		doReturn(configPathMock).when(encryptionParametersDataGeneratorService).makePath(configPathMock);
		doReturn(jsonObjectMock).when(encryptionParametersDataGeneratorService).getJsonObject(anyString());
		doThrow(new IOException()).when(encryptionParametersDataGeneratorService).getOutputStream(configPathMock);

		DataGeneratorResponse result = encryptionParametersDataGeneratorService.generate(electionEventId);
		assertFalse(result.isSuccessful());
	}

	@Test
	public void generateThrowIOExceptionFromWrite() throws IOException {
		electionEventId = "12345";
		String electionEvent = "";

		when(configPathMock.resolve(anyString())).thenReturn(configPathMock);
		when(pathResolverMock.resolve(anyString())).thenReturn(configPathMock);

		doReturn(configPathMock).when(encryptionParametersDataGeneratorService).makePath(configPathMock);
		doReturn(outputStreamMock).when(encryptionParametersDataGeneratorService).getOutputStream(configPathMock);
		doReturn(jsonObjectMock).when(encryptionParametersDataGeneratorService).getJsonObject(anyString());

		when(electionEventRepositoryMock.find(electionEventId)).thenReturn(electionEvent);

		when(jsonObjectMock.getJsonObject(anyString())).thenReturn(jsonObjectMock);
		when(jsonObjectMock.getJsonObject(anyString())).thenReturn(jsonObjectMock);


		doThrow(new IOException()).when(outputStreamMock).write(any(byte[].class));

		DataGeneratorResponse result = encryptionParametersDataGeneratorService.generate(electionEventId);
		assertFalse(result.isSuccessful());
	}

	@Test
	public void generateThrowIOExceptionFromFlush() throws IOException {
		electionEventId = "12345";
		String electionEvent = "";


		when(configPathMock.resolve(anyString())).thenReturn(configPathMock);
		when(pathResolverMock.resolve(anyString())).thenReturn(configPathMock);
		when(jsonObjectMock.getJsonObject(anyString())).thenReturn(jsonObjectMock);
		when(jsonObjectMock.getJsonObject(anyString())).thenReturn(jsonObjectMock);
		when(electionEventRepositoryMock.find(electionEventId)).thenReturn(electionEvent);

		doReturn(configPathMock).when(encryptionParametersDataGeneratorService).makePath(configPathMock);
		doReturn(outputStreamMock).when(encryptionParametersDataGeneratorService).getOutputStream(configPathMock);
		doReturn(jsonObjectMock).when(encryptionParametersDataGeneratorService).getJsonObject(anyString());

		doNothing().when(outputStreamMock).write(any(byte[].class));
		doThrow(new IOException()).when(outputStreamMock).flush();

		DataGeneratorResponse result = encryptionParametersDataGeneratorService.generate(electionEventId);
		assertFalse(result.isSuccessful());
	}

	@Test
	public void generate() throws IOException {
		electionEventId = "12345";
		String electionEvent = "";

		when(configPathMock.resolve(anyString())).thenReturn(configPathMock);
		when(pathResolverMock.resolve(anyString())).thenReturn(configPathMock);
		when(electionEventRepositoryMock.find(electionEventId)).thenReturn(electionEvent);
		when(jsonObjectMock.getJsonObject(anyString())).thenReturn(jsonObjectMock);
		when(jsonObjectMock.getJsonObject(anyString())).thenReturn(jsonObjectMock);


		doReturn(configPathMock).when(encryptionParametersDataGeneratorService).makePath(configPathMock);
		doReturn(outputStreamMock).when(encryptionParametersDataGeneratorService).getOutputStream(configPathMock);
		doReturn(jsonObjectMock).when(encryptionParametersDataGeneratorService).getJsonObject(anyString());

		doNothing().when(outputStreamMock).write(any(byte[].class));
		doNothing().when(outputStreamMock).flush();

		DataGeneratorResponse result = encryptionParametersDataGeneratorService.generate(electionEventId);
		assertTrue(result.isSuccessful());
	}
}
