added test case and fix for records contained in arrays

git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@980253 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/js/test/src/test/TestHandler.java b/lib/js/test/src/test/TestHandler.java
index 727a32b..f2c944f 100644
--- a/lib/js/test/src/test/TestHandler.java
+++ b/lib/js/test/src/test/TestHandler.java
@@ -48,7 +48,7 @@
     }
 
     public void testException(String arg) throws Xception, TException {
-        throw new Xception(1,"server test exception");       
+        throw new Xception(1,arg);       
     }
 
     public int testI32(int thing) throws TException {
diff --git a/lib/js/test/test.html b/lib/js/test/test.html
index 0e2ee42..708db41 100644
--- a/lib/js/test/test.html
+++ b/lib/js/test/test.html
@@ -1,95 +1,142 @@
-<!--
-  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.
--->
-
-<html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
-  <title>Thrift Javascript Bindings - Example</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <title>Thrift Javascript Bindings: Unit Test</title>
 
-  <script src="/thrift.js"                 type="text/javascript"></script>
-  <script src="gen-js/ThriftTest_types.js" type="text/javascript"></script>
-  <script src="gen-js/ThriftTest.js"       type="text/javascript"></script>
+  <script src="/thrift.js"                  type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
 
-  <!-- for async example -->
-  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
+  <!-- jQuery -->
+  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" charset="utf-8"></script>
+
+  <!-- QUnit Test framework-->
+  <script type="text/javascript" src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js" charset="utf-8"></script>
+  <link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" type="text/css" media="screen" />
+
+  <script type="text/javascript" charset="utf-8">
+  //<![CDATA[
+  $(document).ready(function(){
+    var transport = new Thrift.Transport("/service")
+    var protocol  = new Thrift.Protocol(transport)
+    var client    = new ThriftTest.ThriftTestClient(protocol)
+
+
+    module("Base Types");
+
+    test("String", function() {
+      equals(client.testString("works"), "works");
+    });
+    test("String UTF-8", function() {
+      var languagesUtf8 = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
+      equals(client.testString(languagesUtf8), languagesUtf8);
+    });
+    test("Double", function() {
+      equals(client.testDouble(3.14), 3.14);
+    });
+    test("Byte", function() {
+      equals(client.testByte(0x01), 0x01);
+    });
+    test("I32", function() {
+      equals(client.testI32(Math.pow(2,30)), Math.pow(2,30));
+    });
+    test("I64", function() {
+      equals(client.testI64(Math.pow(2,60)), Math.pow(2,60));
+    });
+
+
+    module("Structured Types");
+
+    var insanity  = new ThriftTest.Insanity()
+    insanity.userMap[ThriftTest.Numberz.ONE] = 1
+    insanity.userMap[ThriftTest.Numberz.TWO] = 2
+
+    var xtr = new ThriftTest.Xtruct()
+    xtr.string_thing = 'worked'
+    insanity.xtructs.push(xtr)
+
+    var xtr2= new ThriftTest.Xtruct2()
+    xtr2.struct_thing = xtr
+
+    var list = [1,2,3]
+
+    test("Struct", function() {
+      equals(client.testStruct(xtr).string_thing, "worked");
+    });
+    test("Nest", function() {
+      equals(client.testNest(xtr2).struct_thing.string_thing, "worked");
+    });
+    test("Map", function() {
+      equals(client.testMap(insanity.userMap)[ThriftTest.Numberz.ONE], 1);
+    });
+    test("List", function() {
+      same(client.testList(list), list);
+    });
+    test("Set", function() {
+      same(client.testSet(list), list);
+    });
+    test("Enum", function() {
+      equals(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE);
+    });
+
+
+    module("Exception");
+
+    test("Xception", function() {
+      expect(2);
+      try{
+        client.testException("Xception");
+      }catch(e){
+        equals(e.errorCode, 1);
+        equals(e.message, "Xception");
+      }
+    });
+
+    test("ApplicationException", function() {
+      expect(1);
+      try{
+        client.testException("ApplicationException");
+      }catch(e){
+        equals(e.message, "ApplicationException");
+      }
+    });
+
+    test("no Exception", function() {
+      expect(1);
+      try{
+        client.testException("no Exception");
+      }catch(e){
+        equals(e.message, "no Exception");
+      }
+    });
+
+
+    module("Insanity");
+
+    test("testInsanity", function() {
+      var res = client.testInsanity(insanity);
+      equals(res["1"]["1"].xtructs[0].string_thing, "worked");
+    });
+
+  });
+  //]]>
+  </script>
 
 </head>
-<body id="body">
+<body>
 
-<script language="javascript">
-
-  //create client
-  var transport = new Thrift.Transport("/service")
-  var protocol  = new Thrift.Protocol(transport)
-  var client    = new ThriftTest.ThriftTestClient(protocol)
-
-  //create insanity obj
-  var insanity  = new ThriftTest.Insanity()
-  insanity.userMap[ThriftTest.Numberz.ONE] = 1
-  insanity.userMap[ThriftTest.Numberz.TWO] = 2
-
-  var xtr = new ThriftTest.Xtruct()
-  xtr.string_thing = 'worked'
-  insanity.xtructs.push(xtr)
-
-  var xtr2= new ThriftTest.Xtruct2()
-  xtr2.struct_thing = xtr
-
-  var list = [1,2,3]
-
-  //run tests synchronously
-
-  document.write("<h2><u>Thrift Javascript Bindings</u></h2>")
-  document.write("<h2>Synchronous Example</h2>")
-  document.write("client.testString() => "+(client.testString("works")     == "works")+"<br/>")
-  document.write("client.testString(utf-8) => "+(client.testString("a‡Ž’—œe")   == "a‡Ž’—œe")+"<br/>")
-  document.write("client.testDouble() => "+(client.testDouble(3.14)        == 3.14)+"<br/>")
-  document.write("client.testByte()   => "+(client.testByte(0x01)          == 0x01)+"<br/>")
-  document.write("client.testI32()    => "+(client.testI32(Math.pow(2,30)) == Math.pow(2,30))+"<br/>")
-  document.write("client.testI64()    => "+(client.testI64(Math.pow(2,60)) == Math.pow(2,60))+"<br/>")
-  document.write("client.testStruct() => "+(client.testStruct(xtr).string_thing == "worked")+"<br/>")
-  document.write("client.testNest()   => "+(client.testNest(xtr2).struct_thing.string_thing == "worked")+"<br/>")
-  document.write("client.testMap()    => "+(client.testMap(insanity.userMap)[ThriftTest.Numberz.ONE] == 1)+"<br/>")
-  document.write("client.testList()   => "+(client.testList(list).length == 3 && client.testList(list)[1] == 2)+"<br/>")
-  document.write("client.testSet()    => "+(client.testSet(list).length == 3)+"<br/>")
-  document.write("client.testEnum()   => "+(client.testEnum(ThriftTest.Numberz.ONE) == ThriftTest.Numberz.ONE)+"<br/>")
-
-  document.write("client.testException() => ")
-  try{
-    client.testException("go")
-    document.write("false<br/>")
-  }catch(e){
-    document.write("true<br/>")
-  }
-
-  document.write("client.testInsanity() => ")
-  var res = client.testInsanity(insanity)
-
-  document.write((res["1"]["1"].xtructs[0].string_thing == "worked")+"<br/>")
+  <script type="text/javascript" charset="utf-8">
+  //<![CDATA[
 
   //////////////////////////////////
   //Run same tests asynchronously
-
+/*
   var transport = new Thrift.Transport()
   var protocol  = new Thrift.Protocol(transport)
   var client    = new ThriftTest.ThriftTestClient(protocol)
 
-  document.write("<h2>Asynchronous Example</h2>")
+  document.write("<h2>Asynchronous Example<\/h2>")
   jQuery.ajax({
      url: "/service",
      data: client.send_testI32(Math.pow(2,30)),
@@ -125,10 +172,18 @@
 
      }
   })
+*/
 
-
-
-</script>
-
+  //]]>
+  </script>
+  <h1 id="qunit-header">Thrift Javascript Bindings: Unit Test (<a href="https://svn.apache.org/repos/asf/incubator/thrift/trunk/test/ThriftTest.thrift">ThriftTest.thrift</a>)</h1>
+  <h2 id="qunit-banner"></h2>
+  <h2 id="qunit-userAgent"></h2>
+  <ol id="qunit-tests"><li><!-- get valid xhtml strict--></li></ol>
+  <p>
+      <a href="http://validator.w3.org/check/referer"><img
+          src="http://www.w3.org/Icons/valid-xhtml10"
+          alt="Valid XHTML 1.0!" height="31" width="88" /></a>
+  </p>
 </body>
 </html>
diff --git a/lib/js/thrift.js b/lib/js/thrift.js
index 5e9c89e..04a34d1 100644
--- a/lib/js/thrift.js
+++ b/lib/js/thrift.js
@@ -54,7 +54,7 @@
 }
 
 
-Thrift.TApplicationException = {
+Thrift.TApplicationExceptionType = {
     "UNKNOWN"              : 0,
     "UNKNOWN_METHOD"       : 1,
     "INVALID_MESSAGE_TYPE" : 2,
@@ -401,7 +401,9 @@
         var p = this.tpos.pop()
 
         while( this.tstack.length > p+1 ){
-            this.tstack[p].push(this.tstack.pop())
+            var tmpVal = this.tstack[p+1]
+            this.tstack.splice(p+1, 1)
+            this.tstack[p].push(tmpVal)
         }
 
         this.tstack[p] = '['+this.tstack[p].join(",")+']';
@@ -416,7 +418,9 @@
         var p = this.tpos.pop()
 
         while( this.tstack.length > p+1 ){
-            this.tstack[p].push(this.tstack.pop())
+            var tmpVal = this.tstack[p+1]
+            this.tstack.splice(p+1, 1)
+            this.tstack[p].push(tmpVal)
         }
 
         this.tstack[p] = '['+this.tstack[p].join(",")+']';
@@ -486,13 +490,19 @@
     },
 
     readStructBegin : function(name){
-        var r = {};
-        r["fname"] = '';
-             
-        return r;
+        var r = {}
+        r["fname"] = ''
+        
+        //incase this is an array of structs
+        if(this.rstack[this.rstack.length-1] instanceof Array)
+            this.rstack.push(this.rstack[this.rstack.length-1].shift())
+     
+        return r
     },
 
     readStructEnd : function(){
+        if(this.rstack[this.rstack.length-2] instanceof Array)
+            this.rstack.pop()
     },
 
     readFieldBegin : function(){
@@ -578,8 +588,7 @@
         
         this.rpos.push(this.rstack.length);
         this.rstack.push(list)
-        
-        
+             
         return r;
     },
 
@@ -616,19 +625,24 @@
     },
    
 
-    readI32 : function(){
-        var f = this.rstack[this.rstack.length-1]
+    readI32 : function(f){
+        if(f == undefined)
+            f = this.rstack[this.rstack.length-1]
+        
         var r = {}    
             
         if(f instanceof Array){
-            r["value"] = f.pop()
-        
+            if(f.length == 0)
+                r["value"] = undefined
+            else
+                r["value"] = f.shift()
+
         }else if(f instanceof Object){
            for(var i in f){
                 if(i == null) continue
                 this.rstack.push(f[i])
                 delete f[i]  
-                
+                                  
                 r["value"] = i
                 break
            }
@@ -636,7 +650,6 @@
             r["value"] = f
         }
         
-        
         return r
     },