package org.owasp.esapi.reference.validation;

import junit.framework.Assert;

import org.junit.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.owasp.esapi.Encoder;
import org.owasp.esapi.ValidationErrorList;
import org.owasp.esapi.errors.ValidationException;

public class StringValidationRuleTest {

	@Test
	public void testWhitelistPattern() throws ValidationException {
		
		StringValidationRule validationRule = new StringValidationRule("Alphabetic");
		
		Assert.assertEquals("Magnum44", validationRule.getValid("", "Magnum44"));
		validationRule.addWhitelistPattern("^[a-zA-Z]*");
		try {
			validationRule.getValid("", "Magnum44");
			Assert.fail("Expected Exception not thrown");
		}
		catch (ValidationException ve) {
			Assert.assertNotNull(ve.getMessage());
		}
		Assert.assertEquals("MagnumPI", validationRule.getValid("", "MagnumPI"));
		
	}
	
	@Test
	public void testWhitelistPattern_Invalid() throws ValidationException {
		
		StringValidationRule validationRule = new StringValidationRule("");
		
		//null white list patterns throw IllegalArgumentException
		try {
			String pattern = null;
			validationRule.addWhitelistPattern(pattern);
			Assert.fail("Expected Exception not thrown");
		}
		catch (IllegalArgumentException ie) {
			Assert.assertNotNull(ie.getMessage());
		}
		
		try {
			java.util.regex.Pattern pattern = null;
			validationRule.addWhitelistPattern(pattern);
			Assert.fail("Expected Exception not thrown");
		}
		catch (IllegalArgumentException ie) {
			Assert.assertNotNull(ie.getMessage());
		}
		
		//invalid white list patterns throw PatternSyntaxException
		try {
			String pattern = "_][0}[";
			validationRule.addWhitelistPattern(pattern);
			Assert.fail("Expected Exception not thrown");
		}
		catch (IllegalArgumentException ie) {
			Assert.assertNotNull(ie.getMessage());
		}
	}
	
	@Test
	public void testWhitelist() {
		StringValidationRule validationRule = new StringValidationRule("");
		
		char[] whitelistArray = new char[] {'a', 'b', 'c'};
		Assert.assertEquals("abc", validationRule.whitelist("12345abcdef", whitelistArray));
	}
	
	@Test
	public void testBlacklistPattern() throws ValidationException {
		
		StringValidationRule validationRule = new StringValidationRule("NoAngleBrackets");
		
		Assert.assertEquals("beg <script> end", validationRule.getValid("", "beg <script> end"));
		validationRule.addBlacklistPattern("^.*(<|>).*");
		try {
			validationRule.getValid("", "beg <script> end");
			Assert.fail("Expected Exception not thrown");
		}
		catch (ValidationException ve) {
			Assert.assertNotNull(ve.getMessage());
		}
		Assert.assertEquals("beg script end", validationRule.getValid("", "beg script end"));
	}
	
	@Test
	public void testBlacklistPattern_Invalid() throws ValidationException {
		
		StringValidationRule validationRule = new StringValidationRule("");
		
		//null black list patterns throw IllegalArgumentException
		try {
			String pattern = null;
			validationRule.addBlacklistPattern(pattern);
			Assert.fail("Expected Exception not thrown");
		}
		catch (IllegalArgumentException ie) {
			Assert.assertNotNull(ie.getMessage());
		}
		
		try {
			java.util.regex.Pattern pattern = null;
			validationRule.addBlacklistPattern(pattern);
			Assert.fail("Expected Exception not thrown");
		}
		catch (IllegalArgumentException ie) {
			Assert.assertNotNull(ie.getMessage());
		}
		
		//invalid black list patterns throw PatternSyntaxException
		try {
			String pattern = "_][0}[";
			validationRule.addBlacklistPattern(pattern);
			Assert.fail("Expected Exception not thrown");
		}
		catch (IllegalArgumentException ie) {
			Assert.assertNotNull(ie.getMessage());
		}
	}	
	
	@Test
	public void testCheckLengths() throws ValidationException {
		
		StringValidationRule validationRule = new StringValidationRule("Max12_Min2");
		validationRule.setMinimumLength(2);
		validationRule.setMaximumLength(12);
		
		Assert.assertTrue(validationRule.isValid("", "12"));
		Assert.assertTrue(validationRule.isValid("", "123456"));
		Assert.assertTrue(validationRule.isValid("", "ABCDEFGHIJKL"));
		
		Assert.assertFalse(validationRule.isValid("", "1"));
		Assert.assertFalse(validationRule.isValid("", "ABCDEFGHIJKLM"));
		
		ValidationErrorList errorList = new ValidationErrorList();
		Assert.assertEquals("1234567890", validationRule.getValid("", "1234567890", errorList));
		Assert.assertEquals(0, errorList.size());
		Assert.assertEquals(null, validationRule.getValid("", "123456789012345", errorList));
		Assert.assertEquals(1, errorList.size());
	}
	
	@Test
	public void testAllowNull() throws ValidationException {
		
		StringValidationRule validationRule = new StringValidationRule("");
		
		Assert.assertFalse(validationRule.isAllowNull());
		Assert.assertFalse(validationRule.isValid("", null));
		
		validationRule.setAllowNull(true);
		Assert.assertTrue(validationRule.isAllowNull());
		Assert.assertTrue(validationRule.isValid("", null));
	}
	
	@Test
	public void testSetCanonicalize() throws ValidationException {
	    String context = "test-scope";
	    String inputString = "SomeInputValue";
	    String encoderReturn = "MockReturnValue";
	    Encoder mockEncoder = Mockito.mock(Encoder.class);
	    Mockito.when(mockEncoder.canonicalize(inputString)).thenReturn(encoderReturn);
	    StringValidationRule testRule = new StringValidationRule(context, mockEncoder);
	    String valid = testRule.getValid(context, inputString);
	    Assert.assertEquals(encoderReturn, valid);
	    Mockito.verify(mockEncoder, Mockito.times(1)).canonicalize(inputString);
	    Mockito.reset(mockEncoder);
	    
	    testRule.setCanonicalize(false);
        valid = testRule.getValid(context, inputString);
        Assert.assertEquals(inputString, valid);
        Mockito.verify(mockEncoder, Mockito.times(0)).canonicalize(inputString);
	}
	
}
