class TestCase::Module::Format {
  use Format;
  use TestCase::Minimal;
  use Point;
  
  static method sprintf_X : int () {
    
    unless (Format->sprintf("%X", [(object)0]) eq "0") {
      return 0;
    }
    
    unless (Format->sprintf("%X", [(object)255]) eq "FF") {
      return 0;
    }
    unless (Format->sprintf("%X", [(object)-1]) eq "FFFFFFFF") {
      return 0;
    }
    unless (Format->sprintf("%X", [(object)10]) eq "A") {
      return 0;
    }
    unless (Format->sprintf("%X", [(object)11]) eq "B") {
      return 0;
    }
    unless (Format->sprintf("%X", [(object)12]) eq "C") {
      return 0;
    }
    unless (Format->sprintf("%X", [(object)13]) eq "D") {
      return 0;
    }
    unless (Format->sprintf("%X", [(object)14]) eq "E") {
      return 0;
    }
    unless (Format->sprintf("%X", [(object)15]) eq "F") {
      return 0;
    }
    unless (Format->sprintf("%08X", [(object)255]) eq "000000FF") {
      return 0;
    }
    
    # Ignore "+"
    unless (Format->sprintf("%+08X", [(object)255]) eq "000000FF") {
      return 0;
    }
    
    # "-" ignores "0" padding
    unless (Format->sprintf("%-08X", [(object)255]) eq "FF      ") {
      return 0;
    }
    
    # Invalid type
    {
      eval {
        Format->sprintf("%X", [(object)(byte)1]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    
    return 1;
  }
  
  static method sprintf_basic : int () {
    
    {
      my $result = Format->sprintf("Foo %d %s %.3f Bar", [(object)123, "abc", 1.115]);
      unless ($result eq "Foo 123 abc 1.115 Bar") {
        return 0;
      }
    }
    
    return 1;
  }
  
  static method sprintf_c : int () {
    unless (Format->sprintf("%c", [(object)'x']) eq "x") { return 0; }
    unless (Format->sprintf("%05c", [(object)'x']) eq "0000x") { return 0; }
    unless (Format->sprintf("%-5c", [(object)'x']) eq "x    ") { return 0; }
    unless (Format->sprintf("%+c", [(object)'x']) eq "x") { return 0; }
    
    # UTF-8
    {
      unless (Format->sprintf("%c", [(object)Fn->ord("あ")]) eq "あ") { return 0; }
      
      unless (Format->sprintf("%05c", [(object)Fn->ord("あ")]) eq "00あ") { return 0; }
      unless (Format->sprintf("%-5c", [(object)Fn->ord("あ")]) eq "あ  ") { return 0; }
      unless (Format->sprintf("%+c", [(object)Fn->ord("あ")]) eq "あ") { return 0; }
    }
    
    # Invalid UTF-8
    unless (Format->sprintf("%c", [(object)0xD800]) eq "?") { return 0; }
    {
      eval {
        Format->sprintf("%c", [(object)"str"]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    return 1;
  }
  
  static method sprintf_d : int () {
    unless (Format->sprintf("%d", [(object)123]) eq "123") {
      return 0;
    }
    
    unless (Format->sprintf("%d", [(object)123]) eq "123") {
      return 0;
    }
    unless (Format->sprintf("%5d", [(object)123]) eq "  123") {
      return 0;
    }
    unless (Format->sprintf("%05d", [(object)123]) eq "00123") {
      return 0;
    }
    unless (Format->sprintf("%+5d", [(object)123]) eq " +123") {
      return 0;
    }
    unless (Format->sprintf("%-5d", [(object)123]) eq "123  ") {
      return 0;
    }
    unless (Format->sprintf("%-05d", [(object)123]) eq "123  ") {
      return 0;
    }
    unless (Format->sprintf("%d", [(object)-123]) eq "-123") {
      return 0;
    }
    unless (Format->sprintf("%+5d", [(object)-123]) eq " -123") {
      return 0;
    }
    unless (Format->sprintf("%d", [(object)-2147483648]) eq "-2147483648") {
      return 0;
    }
    unless (Format->sprintf("%3d", [(object)-2147483648]) eq "-2147483648") {
      return 0;
    }
    
    
    # Invalid type
    {
      eval {
        Format->sprintf("%d", [(object)(byte)1]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    
    return 1;
  }
  
  static method sprintf_exception : int () {
    {
      # Invalid conversion (end of string)
      eval {
        Format->sprintf("%d%", [(object)1]);
      };
      unless ($@ && Fn->index($@, "Invalid conversion in sprintf: end of string", 0) > -1) {
        warn("got error: $@");
        return 0;
      }
      
    }
    {
      # Invalid conversion (unknown specifier)
      eval {
        Format->sprintf("%d%k", [(object)1, 2]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    {
      # Invalid conversion (no type)
      eval {
        Format->sprintf("%012.3", [(object)3.14]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    {
      # Missing argument
      eval {
        Format->sprintf("%d%d", [(object)1]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    {
      my $string = "abc\n";
      my $ret = Fn->chompr($string);
      unless ($ret eq "abc") {
        return 0;
      }
    }
    {
      my $string = "abc";
      my $ret = Fn->chompr($string);
      unless ($ret eq "abc") {
        return 0;
      }
    }
    {
      my $string = "";
      my $ret = Fn->chompr($string);
      unless ($ret eq "") {
        return 0;
      }
    }
    
    return 1;
  }
  
  static method sprintf_extra : int () {
    unless (Format->sprintf("%d%%",    [(object)1]) eq "1%") { return 0; }
    unless (Format->sprintf("%%%d",    [(object)1]) eq "%1") { return 0; }
    unless (Format->sprintf("%d%%str", [(object)1]) eq "1%str") { return 0; }
    return 1;
  }
  
  static method sprintf_f : int () {
    unless (Format->sprintf("%f", [(object)3.1415]) eq "3.141500") { return 0; }
    unless (Format->sprintf("%.2f", [(object)3.1415]) eq "3.14") { return 0; }
    unless (Format->sprintf("%.10f", [(object)3.14]) eq "3.1400000000") { return 0; }
    unless (Format->sprintf("%012.6f", [(object)3.14]) eq "00003.140000") { return 0; }
    unless (Format->sprintf("%+12.6f", [(object)3.14]) eq "   +3.140000") { return 0; }
    unless (Format->sprintf("%-12.6f", [(object)3.14]) eq "3.140000    ") { return 0; }
    unless (Format->sprintf("%+-12.6f", [(object)3.14]) eq "+3.140000   ") { return 0; }
    unless (Format->sprintf("%.300f", [(object)1.0]) eq ("1." . Fn->repeat("0", 300))) { return 0; }
    unless (Format->sprintf("%10.300f", [(object)1.0]) eq ("1." . Fn->repeat("0", 300))) { return 0; }
    
    {
      my $output = Format->sprintf("%f", [(object)9.9e+300f]);
      
      warn "[Test Output]$output";
      
      unless ($output eq "inf") {
        warn $output;
        return 0;
      }
    }
    
    {
      my $output = Format->sprintf("%f", [(object)-9.9e+300f]);
      
      warn "[Test Output]$output";
      
      unless ($output eq "-inf") {
        warn $output;
        return 0;
      }
    }
    
    {
      my $output = Format->sprintf("%f", [(object)(0.0f / 0.0f)]);
      
      unless ($output eq "nan" || $output eq "-nan") {
        warn $output;
        return 0;
      }
    }
    
    # Float
    {
      unless (Format->sprintf("%.2f", [(object)3.1415f]) eq "3.14") { return 0; }
    }
    
    {
      eval {
        Format->sprintf("%f", [(object)"str"]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    return 1;
  }
  
  static method sprintf_g : int () {
    unless (Format->sprintf("%g", [(object)3.14]) eq "3.14") { return 0; }
    unless (Format->sprintf("%.2g", [(object)3.14]) eq "3.1") { return 0; }
    unless (Format->sprintf("%-+10.2g", [(object)3.14]) eq "+3.1      ") { return 0; }
    
    unless (Format->sprintf("%g", [(object)3.14f]) eq "3.14") { return 0; }
    
    {
      my $output = Format->sprintf("%g", [(object)9.9e+300f]);
      
      unless ($output eq "inf") {
        warn $output;
        return 0;
      }
    }
    
    {
      my $output = Format->sprintf("%g", [(object)-9.9e+300f]);
      
      warn "[Test Output]$output";
      
      unless ($output eq "-inf") {
        warn $output;
        return 0;
      }
    }
    
    {
      my $output = Format->sprintf("%g", [(object)(0.0f / 0.0f)]);
      
      unless ($output eq "nan" || $output eq "-nan") {
        warn $output;
        return 0;
      }
    }
    
    {
      eval {
        Format->sprintf("%g", [(object)"str"]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    return 1;
  }
  
  static method sprintf_lX : int () {
    
    unless (Format->sprintf("%lX", [(object)0L]) eq "0") {
      return 0;
    }
    unless (Format->sprintf("%lX", [(object)255L]) eq "FF") {
      return 0;
    }
    unless (Format->sprintf("%lX", [(object)-1L]) eq "FFFFFFFFFFFFFFFF") {
      return 0;
    }
    unless (Format->sprintf("%08lX", [(object)255L]) eq "000000FF") {
      return 0;
    }
    
    # Ignore "+"
    unless (Format->sprintf("%+08lX", [(object)255L]) eq "000000FF") {
      return 0;
    }
    
    # "-" ignores "0" padding
    unless (Format->sprintf("%-08lX", [(object)255L]) eq "FF      ") {
      return 0;
    }
    
    # Invalid type
    {
      eval {
        Format->sprintf("%lX", [(object)1]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    
    return 1;
  }
  
  static method sprintf_ld : int () {
    unless (Format->sprintf("%ld", [(object)10000000000L]) eq "10000000000") { return 0; }
    unless (Format->sprintf("%013ld", [(object)12345678901L]) eq "0012345678901") { return 0; }
    unless (Format->sprintf("%+13ld", [(object)12345678901L]) eq " +12345678901") { return 0; }
    unless (Format->sprintf("%-13ld", [(object)12345678901L]) eq "12345678901  ") { return 0; }
    unless (Format->sprintf("%ld", [(object)-9223372036854775808L]) eq "-9223372036854775808") {
      return 0;
    }
    unless (Format->sprintf("%3ld", [(object)-9223372036854775808L]) eq "-9223372036854775808") {
      return 0;
    }
    {
      eval {
        Format->sprintf("%ld", [(object)"str"]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    {
      eval {
        Format->sprintf("%l", [(object)1L]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    return 1;
  }
  
  static method sprintf_lu : int () {
    unless (Format->sprintf("%lu", [(object)10000000000L]) eq "10000000000") { return 0; }
    unless (Format->sprintf("%013lu", [(object)12345678901L]) eq "0012345678901") { return 0; }
    unless (Format->sprintf("%+13lu", [(object)12345678901L]) eq "  12345678901") { return 0; }
    unless (Format->sprintf("%-13lu", [(object)12345678901L]) eq "12345678901  ") { return 0; }
    unless (Format->sprintf("%lu", [(object)-1L]) eq "18446744073709551615") { return 0; }
    {
      eval {
        Format->sprintf("%ld", [(object)"str"]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    {
      eval {
        Format->sprintf("%l", [(object)1L]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    return 1;
  }
  
  static method sprintf_lx : int () {
    
    unless (Format->sprintf("%lx", [(object)0L]) eq "0") {
      return 0;
    }
    unless (Format->sprintf("%lx", [(object)255L]) eq "ff") {
      return 0;
    }
    unless (Format->sprintf("%lx", [(object)-1L]) eq "ffffffffffffffff") {
      return 0;
    }
    unless (Format->sprintf("%08lx", [(object)255L]) eq "000000ff") {
      return 0;
    }
    
    # Ignore "+"
    unless (Format->sprintf("%+08lx", [(object)255L]) eq "000000ff") {
      return 0;
    }
    
    # "-" ignores "0" padding
    unless (Format->sprintf("%-08lx", [(object)255L]) eq "ff      ") {
      return 0;
    }
    
    # Invalid type
    {
      eval {
        Format->sprintf("%lx", [(object)1]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    
    return 1;
  }
  
  static method sprintf_p_value : string () {
    my $string = "abc";
    
    my $formatted_string = Format->sprintf("%p", [(object)$string]);
    
    return $formatted_string;
  }
  static method sprintf_s : int () {
    unless (Format->sprintf("%s", [(object)"ABC"]) eq "ABC") { return 0; }
    unless (Format->sprintf("%05s", [(object)"str"]) eq "00str") { return 0; }
    unless (Format->sprintf("%-5s", [(object)"str"]) eq "str  ") { return 0; }
    unless (Format->sprintf("%+s", [(object)"str"]) eq "str") { return 0; }
    
    unless (Format->sprintf("%s", [(object)1]) eq "1") {
      return 0;
    }
    
    # ""
    {
      my $value = "";
      my $ret = Format->sprintf("%s", [(object)$value]);
      unless ($ret eq "") {
        return 0;
      }
    }
    
    # undef
    {
      my $value = (string)undef;
      my $ret = Format->sprintf("%s", [(object)$value]);
      unless ($ret eq "") {
        return 0;
      }
    }
    
    return 1;
  }
  
  static method sprintf_u : int () {
    unless (Format->sprintf("%u", [(object)123]) eq "123") { return 0; }
    unless (Format->sprintf("%05u", [(object)123]) eq "00123") { return 0; }
    unless (Format->sprintf("%+5u", [(object)123]) eq "  123") { return 0; }
    unless (Format->sprintf("%-5u", [(object)123]) eq "123  ") { return 0; }
    unless (Format->sprintf("%u", [(object)-1]) eq "4294967295") { return 0; }

    {
      eval {
        Format->sprintf("%d", [(object)"str"]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    return 1;
  }
  
  static method sprintf_x : int () {
    
    unless (Format->sprintf("%x", [(object)0]) eq "0") {
      return 0;
    }
    unless (Format->sprintf("%x", [(object)255]) eq "ff") {
      return 0;
    }
    unless (Format->sprintf("%x", [(object)-1]) eq "ffffffff") {
      return 0;
    }
    unless (Format->sprintf("%08x", [(object)255]) eq "000000ff") {
      return 0;
    }
    
    # Ignore "+"
    unless (Format->sprintf("%+08x", [(object)255]) eq "000000ff") {
      return 0;
    }
    
    # "-" ignores "0" padding
    unless (Format->sprintf("%-08x", [(object)255]) eq "ff      ") {
      return 0;
    }
    
    # Invalid type
    {
      eval {
        Format->sprintf("%x", [(object)(byte)1]);
      };
      unless ($@) {
        return 0;
      }
      
    }
    
    return 1;
  }

  static method sprintf_p : int () {
    {
      my $point = Point->new;
      my $formatted = Format->sprintf("%p", [(object)$point]);
      
      warn "[Test Output]$formatted";
      
      unless ($formatted->[0] == '0') {
        return 0;
      }
      unless ($formatted->[1] == 'x') {
        return 0;
      }
      unless (Fn->is_hex_digit($formatted->[2])) {
        return 0;
      }
      unless (Fn->is_hex_digit($formatted->[3])) {
        return 0;
      }
      unless (Fn->is_hex_digit($formatted->[4])) {
        return 0;
      }
      unless (Fn->is_hex_digit($formatted->[5])) {
        return 0;
      }
    }
    return 1;
  }
}
