package hirondelle.web4j.util;

import junit.framework.*;
//import junit.ui.TestRunner;
//import junit.textui.TestRunner;
//import junit.swingui.TestRunner;
import java.util.regex.*;
import java.util.logging.*;
import hirondelle.web4j.util.Util;

/**
 <a href="http://www.junit.org">JUnit</a> test cases for {@link EscapeChars}. 
*/
public final class TESTEscapeChars extends TestCase {

  /**
   Run the test cases.
  */
   public static void main(String args[]) {
     String[] testCaseName = { TESTEscapeChars.class.getName()};
     //Select one of several types of interfaces.
     junit.textui.TestRunner.main(testCaseName);
     //junit.swingui.TestRunner.main(testCaseName);
     //junit.ui.TestRunner.main(testCaseName);
  }

  public TESTEscapeChars(String aName) {
   super(aName);
  }

  // TEST CASES //

  public void testForRegex() {

    //escaped regex does not equal original literal, 
    //yet literal is a match for its own escaped pattern
    testForRegexHasMatch("a.b");
    testForRegexHasMatch("a\\b");
    testForRegexHasMatch("a?b");
    testForRegexHasMatch("a*b");
    testForRegexHasMatch("a+b");
    testForRegexHasMatch("a&b");
    testForRegexHasMatch("{ab}");
    testForRegexHasMatch("ab{}");
    testForRegexHasMatch("a{b}");
    testForRegexHasMatch("{ab");
    testForRegexHasMatch("ab}");
    testForRegexHasMatch("[ab]");
    testForRegexHasMatch("ab]");
    testForRegexHasMatch("[ab");
    testForRegexHasMatch("a[]b");
    testForRegexHasMatch("a^b");
    testForRegexHasMatch("^ab");
    testForRegexHasMatch("ab^");
    testForRegexHasMatch("a$b");
    testForRegexHasMatch("$ab");
    testForRegexHasMatch("ab$");
    testForRegexHasMatch("ab:");
    testForRegexHasMatch(":b:");
    testForRegexHasMatch("a::");
    testForRegexHasMatch("(ab)");
    testForRegexHasMatch("(ab");
    testForRegexHasMatch("ab)");
    testForRegexHasMatch("a(b)");
    testForRegexHasMatch("()ab");
    testForRegexHasMatch("a()b");
    testForRegexHasMatch(".\\?*+&:{}[]()^$");
  }
  
  public void testForHTMLFlow(){
    testHTMLFlow("this", "this", Consts.SUCCESS);
    testHTMLFlow("this ", "this ", Consts.SUCCESS);
    testHTMLFlow(" this", " this", Consts.SUCCESS);
    testHTMLFlow(" ", " ", Consts.SUCCESS);
    testHTMLFlow("This is a test", "This is a test", Consts.SUCCESS);
    testHTMLFlow("This is > test", "This is &gt; test", Consts.SUCCESS);
    testHTMLFlow("This is < test", "This is &lt; test", Consts.SUCCESS);
    testHTMLFlow("This is & test", "This is &amp; test", Consts.SUCCESS);
    testHTMLFlow("This is a 'test'", "This is a &#039;test&#039;", Consts.SUCCESS);
    testHTMLFlow("This is a \"test\"", "This is a &quot;test&quot;", Consts.SUCCESS);
    testHTMLFlow("This is a (test)", "This is a &#040;test&#041;", Consts.SUCCESS);
    testHTMLFlow("This is # test", "This is &#035; test", Consts.SUCCESS);
    testHTMLFlow("This is % test", "This is &#037; test", Consts.SUCCESS);
    testHTMLFlow("This is ; test", "This is &#059; test", Consts.SUCCESS);
    testHTMLFlow("This is + test", "This is &#043; test", Consts.SUCCESS);
    testHTMLFlow("This is - test", "This is &#045; test", Consts.SUCCESS);

    testHTMLFlow("This is ! test", "This is &#033; test", Consts.SUCCESS);
    //testHTMLFlow("This is \n test", "This is &#010; test", Consts.SUCCESS); //this char no longer escaped
    //testHTMLFlow("This is \r test", "This is &#013; test", Consts.SUCCESS); //this char no longer escaped
    testHTMLFlow("This is $ test", "This is &#036; test", Consts.SUCCESS);
    testHTMLFlow("This is * test", "This is &#042; test", Consts.SUCCESS);
    testHTMLFlow("This is . test", "This is &#046; test", Consts.SUCCESS);
    testHTMLFlow("This is / test", "This is &#047; test", Consts.SUCCESS);
    testHTMLFlow("This is : test", "This is &#058; test", Consts.SUCCESS);
    testHTMLFlow("This is = test", "This is &#061; test", Consts.SUCCESS);
    testHTMLFlow("This is ? test", "This is &#063; test", Consts.SUCCESS);
    testHTMLFlow("This is @ test", "This is &#064; test", Consts.SUCCESS);
    testHTMLFlow("This is [ test", "This is &#091; test", Consts.SUCCESS);
    testHTMLFlow("This is \\ test", "This is &#092; test", Consts.SUCCESS);
    testHTMLFlow("This is ] test", "This is &#093; test", Consts.SUCCESS);
    testHTMLFlow("This is ^ test", "This is &#094; test", Consts.SUCCESS);
    testHTMLFlow("This is _ test", "This is &#095; test", Consts.SUCCESS);
    testHTMLFlow("This is ` test", "This is &#096; test", Consts.SUCCESS);
    testHTMLFlow("This is { test", "This is &#123; test", Consts.SUCCESS);
    testHTMLFlow("This is ~ test", "This is &#126; test", Consts.SUCCESS);

    //first twelve 
    testHTMLFlow("<>&\"'()#%+-;", "&lt;&gt;&amp;&quot;&#039;&#040;&#041;&#035;&#037;&#043;&#045;&#059;", Consts.SUCCESS);
    //remainder
    //testHTMLFlow("\t\n\r!$*./:=?@[\\]^_`{|}~", "&#009;&#010;&#013;&#033;&#036;&#042;&#046;&#047;&#058;&#061;&#063;&#064;&#091;&#092;&#093;&#094;&#095;&#096;&#123;&#124;&#125;&#126;", Consts.SUCCESS);
    //testHTMLFlow("This is a test \t\n\r!$*./:=?@[\\]^_`{|}~ This is a test", "This is a test &#009;&#010;&#013;&#033;&#036;&#042;&#046;&#047;&#058;&#061;&#063;&#064;&#091;&#092;&#093;&#094;&#095;&#096;&#123;&#124;&#125;&#126; This is a test", Consts.SUCCESS);

    testHTMLFlow("\t!$*./:=?@[\\]^_`{|}~", "&#009;&#033;&#036;&#042;&#046;&#047;&#058;&#061;&#063;&#064;&#091;&#092;&#093;&#094;&#095;&#096;&#123;&#124;&#125;&#126;", Consts.SUCCESS);
    testHTMLFlow("This is a test \t!$*./:=?@[\\]^_`{|}~ This is a test", "This is a test &#009;&#033;&#036;&#042;&#046;&#047;&#058;&#061;&#063;&#064;&#091;&#092;&#093;&#094;&#095;&#096;&#123;&#124;&#125;&#126; This is a test", Consts.SUCCESS);
    
    testHTMLFlow("This is a test", "This is a test ", Consts.FAILS);
    testHTMLFlow("This is a test", " This is a test", Consts.FAILS);
    testHTMLFlow("This is a test", "This  is a test", Consts.FAILS);
    testHTMLFlow("This is a test", " This is a test ", Consts.FAILS);
    testHTMLFlow("This is > test", "This is > test", Consts.FAILS);
    testHTMLFlow("This is > test", "This is &gt test", Consts.FAILS);
    testHTMLFlow("This is > test", "This is gt; test", Consts.FAILS);
    testHTMLFlow("This is + test", "This is &043; test", Consts.FAILS);
    testHTMLFlow("This is + test", "This is &#043 test", Consts.FAILS);
    testHTMLFlow("This is + test", "This is &#043;  test", Consts.FAILS);
    testHTMLFlow("This is ~ test", "This is &#127; test", Consts.FAILS);
 }

  public void testForReplacementString(){
    testReplacementString("abc", "abc", Consts.SUCCESS);
    testReplacementString("a$b", "a\\$b", Consts.SUCCESS);
    testReplacementString("$1", "\\$1", Consts.SUCCESS);
    testReplacementString("a\\b", "a\\\\b", Consts.SUCCESS);
    testReplacementString("[ab]", "[ab]", Consts.SUCCESS);
    testReplacementString("ab{}*&*()%#^@", "ab{}*&*()%#^@", Consts.SUCCESS);
    
    testReplacementString("abc", "abcd", Consts.FAILS);
    testReplacementString("a$b", "a$b", Consts.FAILS);
    testReplacementString("$1", "$1", Consts.FAILS);
    testReplacementString("a\\b", "a\\b", Consts.FAILS);
  }
  
  public void testForJson(){
    testJson("abc", "abc", Consts.SUCCESS);
    testJson(" \"abc\" ", " \\\"abc\\\" ", Consts.SUCCESS);
    testJson("This is one 'New York Ago'", "This is one 'New York Ago'", Consts.SUCCESS);
    testJson("Joel" + '\t' + "Plaskett", "Joel\\tPlaskett", Consts.SUCCESS);
    testJson("Joel" + '\f' + "Plaskett", "Joel\\fPlaskett", Consts.SUCCESS);
    testJson("JoelPlaskett" + '\b', "JoelPlaskett\\b", Consts.SUCCESS);
    testJson("JoelPlaskett" + '\n', "JoelPlaskett\\n", Consts.SUCCESS);
    testJson("Joel Plaskett" + '\r', "Joel Plaskett\\r", Consts.SUCCESS);
    testJson("Joel Plaskett" + '\r' + '\n' , "Joel Plaskett\\r\\n", Consts.SUCCESS);
    testJson("My name is Flann O'Brien", "My name is Flann O'Brien", Consts.SUCCESS);
    testJson("My \"name\" is Flann O'Brien", "My \\\"name\\\" is Flann O'Brien", Consts.SUCCESS);
    testJson("I am \\ slash", "I am \\\\ slash", Consts.SUCCESS);
    testJson("I am / backslash", "I am \\/ backslash", Consts.SUCCESS);
    testJson("This is \"the\" most \\complex\\ test /of/ all; it has lot's going in inside" + '\n' + '\r', "This is \\\"the\\\" most \\\\complex\\\\ test \\/of\\/ all; it has lot's going in inside\\n\\r" , Consts.SUCCESS);
  }

  // FIXTURE //

   protected void setUp(){
     //empty
   }

   /**
    Re-set test objects.
   */
   protected void tearDown() {
     //empty
   }

   // PRIVATE  //
   
  private static final Logger fLogger = Util.getLogger(TESTEscapeChars.class);  
   
   private void testForRegexHasMatch(String aUnescapedRegex){
     Pattern pattern = Pattern.compile(EscapeChars.forRegex(aUnescapedRegex));
     assertTrue(! pattern.pattern().equals(aUnescapedRegex) );
     Matcher matcher = pattern.matcher(aUnescapedRegex);
     fLogger.fine("Escaped pattern: " + pattern.pattern());
     if ( !matcher.matches() ){
       fail(aUnescapedRegex + " does not match pattern " + pattern.pattern());
     }
   }
   
   private void testHTMLFlow(String aInput, String aExpectedOutput, Boolean aSeekingSuccess){
     String output = EscapeChars.forHTML(aInput);
     if ( aSeekingSuccess ) {
       if ( ! output.equals(aExpectedOutput) ){
         fail("Fail: Output was " + Util.quote(output) + ", expected successful match with " + Util.quote(aExpectedOutput));
       }
     }
     else {
       if ( output.equals(aExpectedOutput) ){
         fail("Fail: Output was " + Util.quote(output) + ", expected failed match with " + Util.quote(aExpectedOutput));
       }
     }
   }
   
   private void testReplacementString(String aInput, String aExpectedOutput, Boolean aSeekingSuccess){
     String output = EscapeChars.forReplacementString(aInput);
     if ( aSeekingSuccess ) {
       if( ! output.equals(aExpectedOutput)) {
         fail("Fail: Output was " + Util.quote(output) + ", but expected " + Util.quote(aExpectedOutput));
       }
     }
     else {
       if ( output.equals(aExpectedOutput) ){
         fail("Fail: Output was " + Util.quote(output) + ", but expected failure to match " + Util.quote(aExpectedOutput));
       }
     }
   }
   
   private void testJson(String aInput, String aExpectedOutput, Boolean aSeekingSuccess){
     String output = EscapeChars.forJSON(aInput);
     if(aSeekingSuccess){
       if( !output.equals(aExpectedOutput) ) {
         fail("Fail: Output was " + Util.quote(output) + ", but expected " + Util.quote(aExpectedOutput));
       }
     }
     else {
       if( output.equals(aExpectedOutput) ){
         fail("Fail: Output was " + Util.quote(output) + ", but expected failure to match " + Util.quote(aExpectedOutput));
       }
     }
   }
}


