/*
 * 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.sysds.test.component.federated;

import org.apache.sysds.runtime.instructions.fed.InitFEDInstruction;
import org.apache.sysds.conf.DMLConfig;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class FederatedUrlParserTest 
{
	@Test(expected = IllegalArgumentException.class)
	public void parseIPAddress_negative_1() {
		// Fail if the input is empty.
		InitFEDInstruction.parseURL("");
	}

	@Test(expected = IllegalArgumentException.class)
	public void parseIPAddress_negative_2() {
		// Fail if there is no file specified.
		InitFEDInstruction.parseURL("192.13.4.2");
	}

	@Test(expected = IllegalArgumentException.class)
	public void parseIPAddress_negative_3() {
		// Fail if there is no file specified even if port is.
		InitFEDInstruction.parseURL("192.13.4.2:132");
	}

	@Test(expected = IllegalArgumentException.class)
	public void parseIPAddress_negative_4() {
		// Fail if the input clearly is an ipv4 address but malformed.
		InitFEDInstruction.parseURL("192.131111.4.2:132/file.txt");
	}

	@Test
	public void parseIPAddress_1() {
		// Parse Ip normally, with filepath and port.
		String[] values = InitFEDInstruction.parseURL("192.13.4.2:132/file.txt");
		assertEquals("192.13.4.2", values[0]);
		assertEquals("132", values[1]);
		assertEquals("file.txt", values[2]);
	}

	@Test
	public void parseIPAddress_2() {
		// Parse Ip normally, with filepath without port specified.
		String[] values = InitFEDInstruction.parseURL("123.123.41.22/file.txt");
		assertEquals("123.123.41.22", values[0]);
		assertEquals(String.valueOf(DMLConfig.DEFAULT_FEDERATED_PORT), values[1]);
		assertEquals("file.txt", values[2]);
	}

	@Test
	public void parseURLAddress_1() {
		// Parse URL address fine with port.
		String[] values = InitFEDInstruction.parseURL("hello.com:132/file.txt");
		assertEquals("hello.com", values[0]);
		assertEquals("132", values[1]);
		assertEquals("file.txt", values[2]);
	}

	@Test
	public void parseURLAddress_2() {
		// parse URL without port.
		String[] values = InitFEDInstruction.parseURL("hello.com/file.txt");
		assertEquals("hello.com", values[0]);
		assertEquals(String.valueOf(DMLConfig.DEFAULT_FEDERATED_PORT), values[1]);
		assertEquals("file.txt", values[2]);
	}

	@Test
	public void parseURLAddress_3() {
		// Parse URL with extended characters
		// Here Japanese: Hello.World
		String[] values = InitFEDInstruction.parseURL("今日は.世界/file.txt");
		assertEquals("今日は.世界", values[0]);
		assertEquals(String.valueOf(DMLConfig.DEFAULT_FEDERATED_PORT), values[1]);
		assertEquals("file.txt", values[2]);
	}

	@Test
	public void parseFilePath_1() {
		// Parse Filepath even if it is nested.
		String[] values = InitFEDInstruction.parseURL("今日は.世界/fu_u_u/bar.txt");
		assertEquals("fu_u_u/bar.txt", values[2]);
	}

	@Test
	public void parseFilePath_2() {
		// Parse Filepath even if it is a folder out.
		String[] values = InitFEDInstruction.parseURL("今日は.世界/../bar.txt");
		assertEquals("../bar.txt", values[2]);
	}

	@Test
	public void parseFilePath_3() {
		// Parse Filepath with special characters.
		String[] values = InitFEDInstruction.parseURL("今日は.世界/../bar世界.txt");
		assertEquals("../bar世界.txt", values[2]);
	}

	@Test
	public void parseStaticFilePath_1() {
		// Parse Filepath even if it is nested.
		String[] values = InitFEDInstruction.parseURL("今日は.世界//fu_u_u/bar.txt");
		assertEquals("/fu_u_u/bar.txt", values[2]);
	}

	@Test
	public void parseStaticFilePath_2() {
		// Parse Filepath even if it is a folder out.
		String[] values = InitFEDInstruction.parseURL("今日は.世界//bar.txt");
		assertEquals("/bar.txt", values[2]);
	}

	@Test
	public void parseStaticFilePath_3() {
		// Parse Filepath with special characters.
		String[] values = InitFEDInstruction.parseURL("今日は.世界//bar世界.txt");
		assertEquals("/bar世界.txt", values[2]);
	}

	@Test(expected = IllegalArgumentException.class)
	public void parseQuery_negative_1() {
		// All Query flags should fail.
		InitFEDInstruction.parseURL("今日は.世界/../bar世界.txt?shouldnothappen");
	}

	@Test(expected = IllegalArgumentException.class)
	public void parseReference_negative_1() {
		// All Reference flags should fail.
		InitFEDInstruction.parseURL("今日は.世界/../bar世界.txt#shouldnothappen");
	}

	@Test(expected = IllegalArgumentException.class)
	public void parseReferenceAndQuery_negative_1() {
		// If both Reference and Query it should still should fail.
		InitFEDInstruction.parseURL("今日は.世界/../bar世界.txt?please#dont");
	}

	@Test
	public void checkDefaultPortIsValid() {
		int defaultPort = DMLConfig.DEFAULT_FEDERATED_PORT;
		// The highest port number allowed.
		int IANA_limit = 49152;
		assertTrue(defaultPort <= IANA_limit);
		assertTrue(defaultPort > 0);
	}
}
