[banshee] [Ossifer.JavaScriptCore] Initial JSC binding



commit dfe251ffd8a94a28997009479a3ca647364a2705
Author: Aaron Bockover <abockover novell com>
Date:   Wed Oct 20 02:09:17 2010 -0400

    [Ossifer.JavaScriptCore] Initial JSC binding
    
    This is my first pass at binding WebKit's JavaScriptCore. JSValue and
    JSObject are mostly complete, along with various APIs from JSContext and
    friends. Literals can be converted to and from managed/JSC land, and
    objects can be constructed (no functions/ctors yet).
    
    New classes can be implemented currently from managed code exposing an
    object to JSC.
    
    Much more work is needed here, but this is a solid start. The end goal
    is interop between .NET/managed code and JavaScript in
    WebKit/JavaScriptCore. It's gonna be fun!

 .../Banshee.WebBrowser/Banshee.WebBrowser.csproj   |   25 ++-
 src/Core/Banshee.WebBrowser/Makefile.am            |   17 ++-
 .../Ossifer.JavaScriptCore/JSClass.cs              |   41 +++
 .../Ossifer.JavaScriptCore/JSClassAttribute.cs     |   37 +++
 .../Ossifer.JavaScriptCore/JSClassDefinition.cs    |  166 ++++++++++++
 .../Ossifer.JavaScriptCore/JSContext.cs            |  109 ++++++++
 .../Ossifer.JavaScriptCore/JSException.cs          |   53 ++++
 .../Ossifer.JavaScriptCore/JSObject.cs             |  113 ++++++++
 .../Ossifer.JavaScriptCore/JSPropertyAttribute.cs  |   39 +++
 .../JSPropertyNameAccumulator.cs                   |   47 ++++
 .../Ossifer.JavaScriptCore/JSString.cs             |  128 +++++++++
 .../Ossifer.JavaScriptCore/JSType.cs               |   40 +++
 .../Ossifer.JavaScriptCore/JSValue.cs              |  281 ++++++++++++++++++++
 .../ManagedPropertyBagClass.cs                     |   80 ++++++
 .../Ossifer.JavaScriptCore/Tests/JSObjectTests.cs  |   93 +++++++
 .../Ossifer.JavaScriptCore/Tests/JSStringTests.cs  |   64 +++++
 .../Ossifer.JavaScriptCore/Tests/JSValueTests.cs   |  248 +++++++++++++++++
 17 files changed, 1575 insertions(+), 6 deletions(-)
---
diff --git a/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj b/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj
index b64d5d2..55666f0 100644
--- a/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj
+++ b/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj
@@ -16,7 +16,7 @@
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
-    <DefineConstants>DEBUG</DefineConstants>
+    <DefineConstants>DEBUG;ENABLE_TESTS</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <OutputPath>..\..\..\bin</OutputPath>
@@ -32,11 +32,9 @@
   <ItemGroup>
     <Reference Include="gtk-sharp">
       <SpecificVersion>False</SpecificVersion>
-      <Package>gtk-sharp-2.0</Package>
     </Reference>
     <Reference Include="gdk-sharp">
       <SpecificVersion>False</SpecificVersion>
-      <Package>gtk-sharp-2.0</Package>
     </Reference>
     <Reference Include="System" />
     <Reference Include="Mono.Posix">
@@ -45,12 +43,12 @@
     </Reference>
     <Reference Include="glib-sharp">
       <SpecificVersion>False</SpecificVersion>
-      <Package>glib-sharp-2.0</Package>
     </Reference>
     <Reference Include="atk-sharp">
       <SpecificVersion>False</SpecificVersion>
-      <Package>gtk-sharp-2.0</Package>
     </Reference>
+    <Reference Include="nunit.core, Version=2.4.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77" />
+    <Reference Include="nunit.framework, Version=2.4.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
@@ -97,6 +95,8 @@
   </ItemGroup>
   <ItemGroup>
     <Folder Include="Banshee.WebBrowser\" />
+    <Folder Include="Ossifer.JavaScriptCore\" />
+    <Folder Include="Ossifer.JavaScriptCore\Tests\" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Banshee.WebBrowser\OssiferWebView.cs" />
@@ -109,5 +109,20 @@
     <Compile Include="Banshee.WebSource\WebBrowserShell.cs" />
     <Compile Include="Banshee.WebSource\WebSource.cs" />
     <Compile Include="Banshee.WebSource\WebView.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSString.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSObject.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSValue.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSType.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSContext.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSClass.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSException.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSClassDefinition.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSClassAttribute.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSPropertyAttribute.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\ManagedPropertyBagClass.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\JSPropertyNameAccumulator.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\Tests\JSValueTests.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\Tests\JSStringTests.cs" />
+    <Compile Include="Ossifer.JavaScriptCore\Tests\JSObjectTests.cs" />
   </ItemGroup>
 </Project>
diff --git a/src/Core/Banshee.WebBrowser/Makefile.am b/src/Core/Banshee.WebBrowser/Makefile.am
index d795a3a..40d1505 100644
--- a/src/Core/Banshee.WebBrowser/Makefile.am
+++ b/src/Core/Banshee.WebBrowser/Makefile.am
@@ -15,7 +15,22 @@ SOURCES =  \
 	Banshee.WebBrowser/OssiferWebView.cs \
 	Banshee.WebSource/WebBrowserShell.cs \
 	Banshee.WebSource/WebSource.cs \
-	Banshee.WebSource/WebView.cs
+	Banshee.WebSource/WebView.cs \
+	Ossifer.JavaScriptCore/JSClass.cs \
+	Ossifer.JavaScriptCore/JSClassAttribute.cs \
+	Ossifer.JavaScriptCore/JSClassDefinition.cs \
+	Ossifer.JavaScriptCore/JSContext.cs \
+	Ossifer.JavaScriptCore/JSException.cs \
+	Ossifer.JavaScriptCore/JSObject.cs \
+	Ossifer.JavaScriptCore/JSPropertyAttribute.cs \
+	Ossifer.JavaScriptCore/JSPropertyNameAccumulator.cs \
+	Ossifer.JavaScriptCore/JSString.cs \
+	Ossifer.JavaScriptCore/JSType.cs \
+	Ossifer.JavaScriptCore/JSValue.cs \
+	Ossifer.JavaScriptCore/ManagedPropertyBagClass.cs \
+	Ossifer.JavaScriptCore/Tests/JSObjectTests.cs \
+	Ossifer.JavaScriptCore/Tests/JSStringTests.cs \
+	Ossifer.JavaScriptCore/Tests/JSValueTests.cs
 
 RESOURCES =  \
 	Resources/loading.html
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSClass.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSClass.cs
new file mode 100644
index 0000000..35dd6f4
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSClass.cs
@@ -0,0 +1,41 @@
+//
+// JSClass.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ossifer.JavaScriptCore
+{
+    public class JSClass
+    {
+        public IntPtr Raw { get; private set; }
+
+        public JSClass (IntPtr raw)
+        {
+            Raw = raw;
+        }
+    }
+}
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSClassAttribute.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSClassAttribute.cs
new file mode 100644
index 0000000..655e45b
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSClassAttribute.cs
@@ -0,0 +1,37 @@
+// 
+// JSClassAttribute.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+
+namespace Ossifer.JavaScriptCore
+{
+    [Flags]
+    public enum JSClassAttribute
+    {
+        None = 0,
+        NoAutomaticPrototype = 1 << 1
+    }
+}
\ No newline at end of file
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSClassDefinition.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSClassDefinition.cs
new file mode 100644
index 0000000..b81f94a
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSClassDefinition.cs
@@ -0,0 +1,166 @@
+// 
+// JSClassDefinition.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+namespace Ossifer.JavaScriptCore
+{
+    public class JSClassDefinition
+    {
+        private struct JSClassDefinitionNative
+        {
+            public int version;
+            public JSClassAttribute attributes;
+
+            public IntPtr class_name;
+            public IntPtr parent_class;
+
+            public IntPtr /* JSStaticValue[] */ static_values;
+            public IntPtr /* JSStaticFunction[] */ static_functions;
+
+            public JSObject.InitializeCallback initialize;
+            public JSObject.FinalizeCallback finalize;
+            public JSObject.HasPropertyCallback has_property;
+            public JSObject.GetPropertyCallback get_property;
+            public JSObject.SetPropertyCallback set_property;
+            public JSObject.DeletePropertyCallback delete_property;
+            public JSObject.GetPropertyNamesCallback get_property_names;
+            public JSObject.CallAsFunctionCallback call_as_function;
+            public JSObject.CallAsConstructorCallback call_as_constructor;
+            public JSObject.HasInstanceCallback has_instance;
+            public JSObject.ConvertToTypeCallback convert_to_type;
+        }
+
+        private JSClassDefinitionNative raw;
+
+        public virtual string ClassName {
+            get { return GetType ().FullName.Replace (".", "_"); }
+        }
+
+        public JSClassDefinition ()
+        {
+            raw = new JSClassDefinitionNative ();
+            raw.class_name = Marshal.StringToHGlobalAnsi (ClassName);
+
+            Override ("OnInitialize", () => raw.initialize = new JSObject.InitializeCallback (JSInitialize));
+            Override ("OnFinalize", () => raw.finalize = new JSObject.FinalizeCallback (JSFinalize));
+            Override ("OnJSHasProperty", () => raw.has_property = new JSObject.HasPropertyCallback (JSHasProperty));
+            Override ("OnJSGetProperty", () => raw.get_property = new JSObject.GetPropertyCallback (JSGetProperty));
+            Override ("OnJSSetProperty", () => raw.set_property = new JSObject.SetPropertyCallback (JSSetProperty));
+            Override ("OnJSDeleteProperty", () => raw.delete_property = new JSObject.DeletePropertyCallback (JSDeleteProperty));
+            Override ("OnJSGetPropertyNames", () => raw.get_property_names = new JSObject.GetPropertyNamesCallback (JSGetPropertyNames));
+        }
+
+        private void Override (string methodName, Action handler)
+        {
+            var method = GetType ().GetMethod (methodName, BindingFlags.Instance | BindingFlags.NonPublic);
+            if (method != null && (method.Attributes & MethodAttributes.VtableLayoutMask) == 0) {
+                handler ();
+            }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSClassCreate (ref JSClassDefinition.JSClassDefinitionNative definition);
+
+        public JSClass CreateClass ()
+        {
+            return new JSClass (JSClassCreate (ref raw));
+        }
+
+        private void JSInitialize (IntPtr ctx, IntPtr obj)
+        {
+            OnJSInitialize (new JSObject (ctx, obj));
+        }
+
+        protected virtual void OnJSInitialize (JSObject obj)
+        {
+        }
+
+        private void JSFinalize (IntPtr obj)
+        {
+            OnJSFinalize (new JSObject (obj));
+        }
+
+        protected virtual void OnJSFinalize (JSObject obj)
+        {
+        }
+
+        private bool JSHasProperty (IntPtr ctx, IntPtr obj, JSString propertyName)
+        {
+            return OnJSHasProperty (new JSObject (ctx, obj), propertyName.Value);
+        }
+
+        protected virtual bool OnJSHasProperty (JSObject obj, string propertyName)
+        {
+            return false;
+        }
+
+        private IntPtr JSGetProperty (IntPtr ctx, IntPtr obj, JSString propertyName, ref IntPtr exception)
+        {
+            var context = new JSContext (ctx);
+            return (OnJSGetProperty (new JSObject (context, obj),
+                propertyName.Value) ?? JSValue.NewNull (context)).Raw;
+        }
+
+        protected virtual JSValue OnJSGetProperty (JSObject obj, string propertyName)
+        {
+            return JSValue.NewUndefined (obj.Context);
+        }
+
+        private bool JSSetProperty (IntPtr ctx, IntPtr obj, JSString propertyName,
+            IntPtr value, ref IntPtr exception)
+        {
+            var context = new JSContext (ctx);
+            return OnJSSetProperty (new JSObject (context, obj), propertyName.Value, new JSValue (context, value));
+        }
+
+        protected virtual bool OnJSSetProperty (JSObject obj, string propertyName, JSValue value)
+        {
+            return false;
+        }
+
+        private bool JSDeleteProperty (IntPtr ctx, IntPtr obj, JSString propertyName, ref IntPtr exception)
+        {
+            return OnJSDeleteProperty (new JSObject (ctx, obj), propertyName.Value);
+        }
+
+        protected virtual bool OnJSDeleteProperty (JSObject obj, string propertyName)
+        {
+            return false;
+        }
+
+        private void JSGetPropertyNames (IntPtr ctx, IntPtr obj, JSPropertyNameAccumulator propertyNames)
+        {
+            OnJSGetPropertyNames (new JSObject (ctx, obj), propertyNames);
+        }
+
+        protected virtual void OnJSGetPropertyNames (JSObject obj, JSPropertyNameAccumulator propertyNames)
+        {
+        }
+    }
+}
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSContext.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSContext.cs
new file mode 100644
index 0000000..02ba9e6
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSContext.cs
@@ -0,0 +1,109 @@
+//
+// JSContext.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright 2010 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ossifer.JavaScriptCore
+{
+    public class JSContext
+    {
+        public const string NATIVE_IMPORT = "libwebkitgtk-1.0.so.0";
+
+        public IntPtr Raw { get; private set; }
+
+        public JSContext (IntPtr raw)
+        {
+            Raw = raw;
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSGlobalContextCreate (IntPtr globalObjectClass);
+
+        public JSContext ()
+        {
+            Raw = JSGlobalContextCreate (IntPtr.Zero);
+        }
+
+        public JSContext (JSClass globalObjectClass)
+        {
+            Raw = JSGlobalContextCreate (globalObjectClass.Raw);
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSEvaluateScript (IntPtr ctx, JSString script,
+            IntPtr thisObject, JSString sourceURL, int startingLineNumber, ref IntPtr exception);
+
+        public JSValue EvaluateScript (JSString script, JSObject thisObject,
+            JSString sourceUrl, int startingLineNumber)
+        {
+            var exception = IntPtr.Zero;
+            var result = JSEvaluateScript (Raw, script,
+                thisObject == null ? IntPtr.Zero : thisObject.Raw,
+                sourceUrl, startingLineNumber, ref exception);
+            JSException.Proxy (this, exception);
+            return new JSValue (result);
+        }
+
+        public JSValue EvaluateScript (string script, JSObject thisObject, string sourceUrl, int startingLineNumber)
+        {
+            var js_script = JSString.New (script);
+            var js_source_url = JSString.New (sourceUrl);
+
+            try {
+                return EvaluateScript (js_script, thisObject, js_source_url, startingLineNumber);
+            } finally {
+                js_script.Release ();
+                js_source_url.Release ();
+            }
+        }
+
+        public JSValue EvaluateScript (string script, JSObject thisObject)
+        {
+            return EvaluateScript (script, thisObject, null, 0);
+        }
+
+        public JSValue EvaluateScript (string script)
+        {
+            return EvaluateScript (script, null, null, 0);
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern void JSGarbageCollect (IntPtr ctx);
+
+        public void GarbageCollect ()
+        {
+            JSGarbageCollect (Raw);
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSContextGetGlobalObject (IntPtr ctx);
+
+        public JSObject GlobalObject {
+            get { return new JSObject (Raw, JSContextGetGlobalObject (Raw)); }
+        }
+    }
+}
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSException.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSException.cs
new file mode 100644
index 0000000..581e4d3
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSException.cs
@@ -0,0 +1,53 @@
+// 
+// JSException.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+
+namespace Ossifer.JavaScriptCore
+{
+    public class JSException : Exception
+    {
+        public JSContext Context { get; private set; }
+
+        internal JSException (JSContext context, string message)
+            : base (message)
+        {
+            Context = context;
+        }
+
+        internal JSException (JSContext context, IntPtr exception)
+            : this (context, "JSON: " + new JSValue (context, exception).ToJsonString ())
+        {
+        }
+
+        internal static void Proxy (JSContext ctx, IntPtr exception)
+        {
+            if (!exception.Equals (IntPtr.Zero)) {
+                throw new JSException (ctx, exception);
+            }
+        }
+    }
+}
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSObject.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSObject.cs
new file mode 100644
index 0000000..37055f1
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSObject.cs
@@ -0,0 +1,113 @@
+// 
+// JSObject.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ossifer.JavaScriptCore
+{
+    public class JSObject : JSValue
+    {
+        public JSObject (IntPtr raw) : base (raw)
+        {
+        }
+
+        public JSObject (IntPtr context, IntPtr raw) : base (context, raw)
+        {
+        }
+
+        public JSObject (JSContext context, IntPtr raw) : base (context, raw)
+        {
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSObjectMake (IntPtr ctx, IntPtr jsClass, IntPtr data);
+
+        public JSObject (JSContext context) :
+            base (context, JSObjectMake (context.Raw, IntPtr.Zero, IntPtr.Zero))
+        {
+        }
+
+        public JSObject (JSContext context, JSClass jsClass)
+            : base (context, JSObjectMake (context.Raw, jsClass.Raw, IntPtr.Zero))
+        {
+        }
+
+        public delegate void
+        InitializeCallback (IntPtr ctx, IntPtr obj);
+
+        public delegate void
+        FinalizeCallback (IntPtr obj);
+
+        public delegate bool
+        HasPropertyCallback (IntPtr ctx, IntPtr obj, JSString propertyName);
+
+        public delegate IntPtr
+        GetPropertyCallback (IntPtr ctx, IntPtr obj, JSString propertyName, ref IntPtr exception);
+        
+        public delegate bool
+        SetPropertyCallback (IntPtr ctx, IntPtr obj, JSString propertyName, IntPtr value, ref IntPtr exception);
+        
+        public delegate bool
+        DeletePropertyCallback (IntPtr ctx, IntPtr obj, JSString propertyName, ref IntPtr exception);
+
+        public delegate void
+        GetPropertyNamesCallback (IntPtr ctx, IntPtr obj, JSPropertyNameAccumulator propertyNames);
+        
+        public delegate IntPtr
+        CallAsFunctionCallback (IntPtr ctx, IntPtr function, IntPtr thisObject, IntPtr argumentCount, IntPtr arguments, ref IntPtr exception);
+
+        public delegate IntPtr
+        CallAsConstructorCallback (IntPtr ctx, IntPtr constructor, IntPtr argumentCount, IntPtr arguments, ref IntPtr exception);
+
+        public delegate bool
+        HasInstanceCallback  (IntPtr ctx, IntPtr constructor, IntPtr possibleInstance, ref IntPtr exception);
+        
+        public delegate IntPtr
+        ConvertToTypeCallback (IntPtr ctx, IntPtr obj, JSType type, ref IntPtr exception);
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern void JSObjectSetProperty (IntPtr ctx, IntPtr obj, JSString propertyName,
+            IntPtr value, JSPropertyAttribute attributes, ref IntPtr exception);
+
+        public void SetProperty (JSContext context, string propertyName, JSValue value, JSPropertyAttribute attributes)
+        {
+            var exception = IntPtr.Zero;
+            var property = JSString.New (propertyName);
+            try {
+                JSObjectSetProperty (context.Raw, Raw, property, value.Raw, attributes, ref exception);
+                JSException.Proxy (context, exception);
+            } finally {
+                property.Release ();
+            }
+        }
+
+        public void SetProperty (string propertyName, JSValue value)
+        {
+            SetProperty (Context, propertyName, value, JSPropertyAttribute.None);
+        }
+    }
+}
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSPropertyAttribute.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSPropertyAttribute.cs
new file mode 100644
index 0000000..b992d46
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSPropertyAttribute.cs
@@ -0,0 +1,39 @@
+// 
+// JSPropertyAttribute.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+
+namespace Ossifer.JavaScriptCore
+{
+    [Flags]
+    public enum JSPropertyAttribute
+    {
+        None = 0,
+        ReadOnly = 1 << 1,
+        DontEnum = 1 << 2,
+        DontDelete = 1 << 3
+    }
+}
\ No newline at end of file
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSPropertyNameAccumulator.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSPropertyNameAccumulator.cs
new file mode 100644
index 0000000..214e522
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSPropertyNameAccumulator.cs
@@ -0,0 +1,47 @@
+// 
+// JSPropertyNameAccumulator.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ossifer.JavaScriptCore
+{
+    public struct JSPropertyNameAccumulator
+    {
+        #pragma warning disable 0169
+        private IntPtr raw;
+        #pragma warning restore 0169
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern void JSPropertyNameAccumulatorAddName (
+            JSPropertyNameAccumulator accumulator, JSString propertyName);
+
+        public void AddName (string propertyName)
+        {
+            JSPropertyNameAccumulatorAddName (this, JSString.New (propertyName));
+        }
+    }
+}
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSString.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSString.cs
new file mode 100644
index 0000000..f05f304
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSString.cs
@@ -0,0 +1,128 @@
+// 
+// JSString.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ossifer.JavaScriptCore
+{
+    public struct JSString
+    {
+        #pragma warning disable 0414
+        private IntPtr raw;
+        #pragma warning restore 0414
+
+        public static JSString Zero {
+            get { return new JSString (IntPtr.Zero); }
+        }
+
+        public JSString (IntPtr raw)
+        {
+            this.raw = raw;
+        }
+
+        internal static string ToStringAndRelease (JSString str)
+        {
+            if (str.Equals (JSString.Zero) || str.raw.Equals (IntPtr.Zero)) {
+                return null;
+            }
+
+            try {
+                return str.Value;
+            } finally {
+                str.Release ();
+            }
+        }
+
+        internal static string ToStringAndRelease (IntPtr raw)
+        {
+            if (raw == IntPtr.Zero) {
+                return null;
+            }
+
+            return ToStringAndRelease (new JSString (raw));
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSStringCreateWithCharacters (IntPtr chars, IntPtr numChars);
+
+        public static JSString New (string str)
+        {
+            if (str == null) {
+                return JSString.Zero;
+            }
+
+            var native = IntPtr.Zero;
+            try {
+                return new JSString (JSStringCreateWithCharacters (
+                    native = Marshal.StringToHGlobalUni (str),
+                    new IntPtr (str.Length)));
+            } finally {
+                Marshal.FreeHGlobal (native);
+            }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern JSString JSStringRetain (JSString str);
+
+        public void Retain ()
+        {
+            JSStringRetain (this);
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern void JSStringRelease (JSString str);
+
+        public void Release ()
+        {
+            if (!Equals (JSString.Zero)) {
+                JSStringRelease (this);
+            }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSStringIsEqual (JSString a, JSString b);
+
+        public bool IsEqual (JSString str)
+        {
+            return JSStringIsEqual (this, str);
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSStringGetLength (JSString str);
+
+        public int Length {
+            get { return JSStringGetLength (this).ToInt32 (); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSStringGetCharactersPtr (JSString str);
+
+        public string Value {
+            get { return Marshal.PtrToStringUni (JSStringGetCharactersPtr (this), Length); }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSType.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSType.cs
new file mode 100644
index 0000000..78a1b76
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSType.cs
@@ -0,0 +1,40 @@
+// 
+// JSType.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+
+namespace Ossifer.JavaScriptCore
+{
+    public enum JSType
+    {
+        Undefined,
+        Null,
+        Boolean,
+        Number,
+        String,
+        Object
+    }
+}
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSValue.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSValue.cs
new file mode 100644
index 0000000..8bf3342
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSValue.cs
@@ -0,0 +1,281 @@
+// 
+// JSValue.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ossifer.JavaScriptCore
+{
+    public class JSValue
+    {
+        public IntPtr Raw { get; private set; }
+        public JSContext Context { get; private set; }
+
+        public JSValue (IntPtr raw)
+        {
+            Raw = raw;
+            Context = null;
+        }
+
+        public JSValue (IntPtr context, IntPtr raw)
+        {
+            Raw = raw;
+            Context = new JSContext (context);
+        }
+
+        public JSValue (JSContext context, IntPtr raw)
+        {
+            Raw = raw;
+            Context = context;
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSValueMakeBoolean (IntPtr ctx, bool value);
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSValueMakeNumber (IntPtr ctx, double value);
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSValueMakeString (IntPtr ctx, JSString value);
+
+        public JSValue (JSContext ctx, bool value) : this (ctx, JSValueMakeBoolean (ctx.Raw, value)) { }
+        public JSValue (JSContext ctx, byte value) : this (ctx, JSValueMakeNumber (ctx.Raw, (double)value)) { }
+        public JSValue (JSContext ctx, sbyte value) : this (ctx, JSValueMakeNumber (ctx.Raw, (double)value)) { }
+        public JSValue (JSContext ctx, short value) : this (ctx, JSValueMakeNumber (ctx.Raw, (double)value)) { }
+        public JSValue (JSContext ctx, ushort value) : this (ctx, JSValueMakeNumber (ctx.Raw, (double)value)) { }
+        public JSValue (JSContext ctx, int value) : this (ctx, JSValueMakeNumber (ctx.Raw, (double)value)) { }
+        public JSValue (JSContext ctx, uint value) : this (ctx, JSValueMakeNumber (ctx.Raw, (double)value)) { }
+        public JSValue (JSContext ctx, long value) : this (ctx, JSValueMakeNumber (ctx.Raw, (double)value)) { }
+        public JSValue (JSContext ctx, ulong value) : this (ctx, JSValueMakeNumber (ctx.Raw, (double)value)) { }
+        public JSValue (JSContext ctx, float value) : this (ctx, JSValueMakeNumber (ctx.Raw, (double)value)) { }
+        public JSValue (JSContext ctx, double value) : this (ctx, JSValueMakeNumber (ctx.Raw, value)) { }
+        public JSValue (JSContext ctx, JSString value) : this (ctx, JSValueMakeString (ctx.Raw, value)) { }
+        public JSValue (JSContext ctx, string value) : this (ctx, JSValueMakeString (ctx.Raw, JSString.New (value))) { }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern JSType JSValueGetType (IntPtr ctx, IntPtr value);
+
+        public JSType JSType {
+            get { return JSValueGetType (Context.Raw, Raw); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueIsUndefined (IntPtr ctx, IntPtr value);
+
+        public bool IsUndefined {
+            get { return JSValueIsUndefined (Context.Raw, Raw); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueIsNull (IntPtr ctx, IntPtr value);
+
+        public bool IsNull {
+            get { return JSValueIsNull (Context.Raw, Raw); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueIsBoolean (IntPtr ctx, IntPtr value);
+
+        public bool IsBoolean {
+            get { return JSValueIsBoolean (Context.Raw, Raw); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueIsNumber (IntPtr ctx, IntPtr value);
+
+        public bool IsNumber {
+            get { return JSValueIsNumber (Context.Raw, Raw); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueIsString (IntPtr ctx, IntPtr value);
+
+        public bool IsString {
+            get { return JSValueIsString (Context.Raw, Raw); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueIsObject (IntPtr ctx, IntPtr value);
+
+        public bool IsObject {
+            get { return JSValueIsObject (Context.Raw, Raw); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueIsObjectOfClass (IntPtr ctx, IntPtr value, IntPtr jsClass);
+
+        public bool IsObjectOfClass (JSClass jsClass)
+        {
+            return JSValueIsObjectOfClass (Context.Raw, Raw, jsClass.Raw);
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueIsEqual (IntPtr ctx, IntPtr a, IntPtr b, ref IntPtr exception);
+
+        public bool IsEqual (JSValue value)
+        {
+            var exception = IntPtr.Zero;
+            var result = JSValueIsEqual (Context.Raw, Raw, value.Raw, ref exception);
+            JSException.Proxy (Context, exception);
+            return result;
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueIsStrictEqual (IntPtr ctx, IntPtr a, IntPtr b);
+
+        public bool IsStrictEqual (JSValue value)
+        {
+            return JSValueIsStrictEqual (Context.Raw, Raw, value.Raw);
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueIsInstanceOfConstructor (IntPtr ctx, IntPtr value,
+            IntPtr constructor, ref IntPtr exception);
+
+        public bool IsInstanceOfConstructor (JSObject constructor)
+        {
+            var exception = IntPtr.Zero;
+            var result = JSValueIsInstanceOfConstructor (Context.Raw, Raw, constructor.Raw, ref exception);
+            JSException.Proxy (Context, exception);
+            return result;
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSValueMakeUndefined (IntPtr ctx);
+
+        public static JSValue NewUndefined (JSContext ctx)
+        {
+            return new JSValue (ctx, JSValueMakeUndefined (ctx.Raw));
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSValueMakeNull (IntPtr ctx);
+
+        public static JSValue NewNull (JSContext ctx)
+        {
+            return new JSValue (ctx, JSValueMakeNull (ctx.Raw));
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSValueMakeFromJSONString (IntPtr ctx, JSString str);
+
+        public static JSValue FromJson (JSContext ctx, JSString json)
+        {
+            var obj = JSValueMakeFromJSONString (ctx.Raw, json);
+            if (obj.Equals (IntPtr.Zero)) {
+                throw new JSException (ctx, "Invalid JSON");
+            }
+
+            return new JSValue (ctx, obj);
+        }
+
+        public static JSValue FromJson (JSContext ctx, string json)
+        {
+            var json_native = JSString.New (json);
+            try {
+                return FromJson (ctx, json_native);
+            } finally {
+                json_native.Release ();
+            }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern bool JSValueToBoolean (IntPtr ctx, IntPtr value);
+
+        public bool BooleanValue {
+            get { return JSValueToBoolean (Context.Raw, Raw); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern double JSValueToNumber (IntPtr ctx, IntPtr value);
+
+        public double NumberValue {
+            get { return JSValueToNumber (Context.Raw, Raw); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSValueToStringCopy (IntPtr ctx, IntPtr value, ref IntPtr exception);
+
+        public string StringValue {
+            get {
+                var exception = IntPtr.Zero;
+                var result = JSString.ToStringAndRelease (JSValueToStringCopy (Context.Raw, Raw, ref exception));
+                JSException.Proxy (Context, exception);
+                return result;
+            }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSValueToObject (IntPtr ctx, IntPtr value, ref IntPtr exception);
+
+        public JSObject ObjectValue {
+            get {
+                var exception = IntPtr.Zero;
+                var result = JSValueToObject (Context.Raw, Raw, ref exception);
+                JSException.Proxy (Context, exception);
+                return new JSObject (result);
+            }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSValueCreateJSONString (IntPtr ctx, IntPtr value, uint indent, ref IntPtr exception);
+
+        public string ToJsonString (uint indent)
+        {
+            var exception = IntPtr.Zero;
+            var result = JSString.ToStringAndRelease (JSValueCreateJSONString (Context.Raw,
+                Raw, indent, ref exception));
+            JSException.Proxy (Context, exception);
+            return result;
+        }
+
+        public string ToJsonString ()
+        {
+            return ToJsonString (0);
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern void JSValueProtect (IntPtr ctx, IntPtr value);
+
+        public void Protect ()
+        {
+            JSValueProtect (Context.Raw, Raw);
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern void JSValueUnprotect (IntPtr ctx, IntPtr value);
+
+        public void Unprotect ()
+        {
+            JSValueUnprotect (Context.Raw, Raw);
+        }
+
+        public override string ToString ()
+        {
+            return ToJsonString (2);
+        }
+    }
+}
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/ManagedPropertyBagClass.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/ManagedPropertyBagClass.cs
new file mode 100644
index 0000000..0204b9d
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/ManagedPropertyBagClass.cs
@@ -0,0 +1,80 @@
+// 
+// ManagedPropertyBagClass.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+
+namespace Ossifer.JavaScriptCore
+{
+    public class ManagedPropertyBagClass : JSClassDefinition
+    {
+        private Dictionary<IntPtr, Dictionary<string, JSValue>> properties
+            = new Dictionary<IntPtr, Dictionary<string, JSValue>> ();
+
+        private Dictionary<string, JSValue> GetBag (JSObject obj)
+        {
+            Dictionary<string, JSValue> bag;
+            if (!properties.TryGetValue (obj.Raw, out bag)) {
+                properties.Add (obj.Raw, bag = new Dictionary<string, JSValue> ());
+            }
+            return bag;
+        }
+
+        protected override void OnJSFinalize (JSObject obj)
+        {
+            properties.Remove (obj.Raw);
+        }
+
+        protected override bool OnJSHasProperty (JSObject obj, string propertyName)
+        {
+            return GetBag (obj).ContainsKey (propertyName);
+        }
+
+        protected override JSValue OnJSGetProperty (JSObject obj, string propertyName)
+        {
+            return GetBag (obj)[propertyName];
+        }
+
+        protected override bool OnJSSetProperty (JSObject obj, string propertyName, JSValue value)
+        {
+            GetBag (obj)[propertyName] = value;
+            return true;
+        }
+
+        protected override bool OnJSDeleteProperty (JSObject obj, string propertyName)
+        {
+            return GetBag (obj).Remove (propertyName);
+        }
+
+        protected override void OnJSGetPropertyNames (JSObject obj, JSPropertyNameAccumulator propertyNames)
+        {
+            foreach (var name in GetBag (obj).Keys) {
+                propertyNames.AddName (name);
+            }
+        }
+    }
+}
+
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSObjectTests.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSObjectTests.cs
new file mode 100644
index 0000000..df839e8
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSObjectTests.cs
@@ -0,0 +1,93 @@
+// 
+// JSObjectTests.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#if ENABLE_TESTS
+
+using System;
+using NUnit.Framework;
+
+namespace Ossifer.JavaScriptCore.Tests
+{
+    [TestFixture]
+    public class JSObjectTests
+    {
+        private JSContext context;
+
+        [TestFixtureSetUp]
+        public void Init ()
+        {
+            context = new JSContext ();
+        }
+
+        [Test]
+        public void GetPropertyOverrideTest ()
+        {
+            var default_obj = new JSObject (context);
+            default_obj.SetProperty ("name", new JSValue (context, "abock"));
+
+            var override_obj = new JSObject (context, new GetPropertyClassTest ().CreateClass ());
+            override_obj.SetProperty ("name", new JSValue (context, "ranger"));
+
+            Assert.AreEqual ("{\"name\":\"abock\"}", default_obj.ToJsonString (0));
+            Assert.AreEqual ("{\"name\":\"always this\"}", override_obj.ToJsonString (0));
+        }
+
+        [Test]
+        public void DeletePropertyTest ()
+        {
+            context.GlobalObject.SetProperty ("a", new JSValue (context, "apple"));
+            context.GlobalObject.SetProperty ("b", new JSValue (context, "bear"));
+            context.GlobalObject.SetProperty ("c", new JSValue (context, "car"));
+
+            Assert.AreEqual ("{\"a\":\"apple\",\"b\":\"bear\",\"c\":\"car\"}",
+                context.GlobalObject.ToJsonString (0));
+
+            context.EvaluateScript ("delete b");
+
+            Assert.AreEqual ("{\"a\":\"apple\",\"c\":\"car\"}",
+                context.GlobalObject.ToJsonString (0));
+
+            context.EvaluateScript ("this.d = a + ' ' + c");
+            context.EvaluateScript ("delete a; delete c");
+
+            Assert.AreEqual ("{\"d\":\"apple car\"}", context.GlobalObject.ToJsonString (0));
+
+            context.EvaluateScript ("delete d");
+
+            Assert.AreEqual ("{}", context.GlobalObject.ToJsonString (0));
+        }
+
+        private class GetPropertyClassTest : JSClassDefinition
+        {
+            protected override JSValue OnJSGetProperty (JSObject obj, string propertyName)
+            {
+                return new JSValue (obj.Context, "always this");
+            }
+        }
+    }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSStringTests.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSStringTests.cs
new file mode 100644
index 0000000..4a27c66
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSStringTests.cs
@@ -0,0 +1,64 @@
+//
+// JSStringTests.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#if ENABLE_TESTS
+
+using System;
+using NUnit.Framework;
+
+namespace Ossifer.JavaScriptCore.Tests
+{
+    [TestFixture]
+    public class JSStringTests
+    {
+        [Test]
+        public void Equality ()
+        {
+            var a_m = "A simple greeting";
+            var a_j = JSString.New (a_m);
+            Assert.AreEqual (a_m, a_j.Value);
+
+            var b_m = a_j.Value;
+            var b_j = JSString.New (b_m);
+            Assert.IsTrue (a_j.IsEqual (b_j));
+        }
+
+        [Test]
+        public void LengthAndEquality ()
+        {
+            var a_m = "Hello World";
+            var a_j = JSString.New (a_m);
+            var b_j = JSString.New (a_j.Value);
+            Assert.AreEqual (a_m.Length, a_j.Length);
+            Assert.AreEqual (a_j.Length, b_j.Length);
+            Assert.AreEqual (a_m, a_j.Value);
+            Assert.AreEqual (a_j.Value, b_j.Value);
+            Assert.IsTrue (a_j.IsEqual (b_j));
+        }
+    }
+}
+
+#endif
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSValueTests.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSValueTests.cs
new file mode 100644
index 0000000..78f5a5a
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSValueTests.cs
@@ -0,0 +1,248 @@
+// 
+// JSValueTests.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#if ENABLE_TESTS
+
+using System;
+using NUnit.Framework;
+
+namespace Ossifer.JavaScriptCore.Tests
+{
+    [TestFixture]
+    public class JSValueTests
+    {
+        private JSContext context;
+
+        [TestFixtureSetUp]
+        public void Init ()
+        {
+            context = new JSContext ();
+        }
+
+        [Test]
+        public void Number ()
+        {
+            var a = new JSValue (context, 10);
+            var b = new JSValue (context, 10.0);
+            var c = new JSValue (context, 10.0f);
+            var d = new JSValue (context, 0);
+            var e = new JSValue (context, -200);
+
+            Assert.IsTrue (a.IsNumber);
+            Assert.IsTrue (b.IsNumber);
+            Assert.IsTrue (c.IsNumber);
+            Assert.IsTrue (d.IsNumber);
+            Assert.IsTrue (e.IsNumber);
+
+            Assert.AreEqual (10.0, a.NumberValue);
+            Assert.AreEqual (10.0, b.NumberValue);
+            Assert.AreEqual (10.0, c.NumberValue);
+            Assert.AreEqual (0, d.NumberValue);
+            Assert.AreEqual (-200, e.NumberValue);
+
+            Assert.AreEqual (false, d.BooleanValue);
+            Assert.AreEqual (true, e.BooleanValue);
+
+            Assert.AreEqual ("-200", e.StringValue);
+
+            Assert.AreEqual (JSType.Number, a.JSType);
+            Assert.AreEqual (JSType.Number, b.JSType);
+            Assert.AreEqual (JSType.Number, c.JSType);
+            Assert.AreEqual (JSType.Number, d.JSType);
+            Assert.AreEqual (JSType.Number, e.JSType);
+        }
+
+        [Test]
+        public void Boolean ()
+        {
+            var a = new JSValue (context, false);
+            var b = new JSValue (context, true);
+
+            Assert.IsTrue (a.IsBoolean);
+            Assert.IsTrue (b.IsBoolean);
+
+            Assert.AreEqual (false, a.BooleanValue);
+            Assert.AreEqual (true, b.BooleanValue);
+
+            Assert.AreEqual (0.0, a.NumberValue);
+            Assert.AreEqual (1.0, b.NumberValue);
+
+            Assert.AreEqual ("false", a.StringValue);
+            Assert.AreEqual ("true", b.StringValue);
+
+            Assert.AreEqual (JSType.Boolean, a.JSType);
+            Assert.AreEqual (JSType.Boolean, b.JSType);
+        }
+
+        [Test]
+        public void String ()
+        {
+            var a = new JSValue (context, "Hello World");
+            var b = new JSValue (context, JSString.New ("Hello World"));
+
+            Assert.IsTrue (a.IsString);
+            Assert.IsTrue (b.IsString);
+
+            Assert.IsTrue (a.IsEqual (b));
+            Assert.IsTrue (a.IsStrictEqual (b));
+            Assert.AreEqual (a.StringValue, b.StringValue);
+
+            Assert.AreEqual (JSType.String, a.JSType);
+            Assert.AreEqual (JSType.String, b.JSType);
+
+            a = new JSValue (context, "Hello World");
+            b = new JSValue (context, JSString.New ("Not the same"));
+
+            Assert.IsFalse (a.IsEqual (b));
+            Assert.IsFalse (a.IsStrictEqual (b));
+        }
+
+        [Test]
+        public void Null ()
+        {
+            var a = JSValue.NewNull (context);
+            Assert.IsTrue (a.IsNull);
+            Assert.AreEqual (JSType.Null, a.JSType);
+            Assert.AreEqual (false, a.BooleanValue);
+            Assert.AreEqual (0, a.NumberValue);
+            Assert.AreEqual ("null", a.StringValue);
+        }
+
+        [Test]
+        public void Undefined ()
+        {
+            var a = JSValue.NewUndefined (context);
+            Assert.IsTrue (a.IsUndefined);
+            Assert.AreEqual (JSType.Undefined, a.JSType);
+            Assert.AreEqual (false, a.BooleanValue);
+            Assert.AreEqual (Double.NaN, a.NumberValue);
+            Assert.AreEqual ("undefined", a.StringValue);
+        }
+
+        [Test]
+        public void EmptyEquality ()
+        {
+            var undef_v = JSValue.NewUndefined (context);
+            var null_v = JSValue.NewNull (context);
+            var number_v = new JSValue (context, 0);
+            var bool_v = new JSValue (context, false);
+            var string_v = new JSValue (context, "");
+
+            Assert.IsTrue (undef_v.IsEqual (undef_v));
+            Assert.IsTrue (undef_v.IsStrictEqual (undef_v));
+            Assert.IsTrue (undef_v.IsEqual (null_v));
+            Assert.IsFalse (undef_v.IsStrictEqual (null_v));
+            Assert.IsFalse (undef_v.IsEqual (number_v));
+            Assert.IsFalse (undef_v.IsStrictEqual (number_v));
+            Assert.IsFalse (undef_v.IsEqual (bool_v));
+            Assert.IsFalse (undef_v.IsStrictEqual (bool_v));
+            Assert.IsFalse (undef_v.IsEqual (string_v));
+            Assert.IsFalse (undef_v.IsStrictEqual (string_v));
+
+            Assert.IsFalse (string_v.IsEqual (undef_v));
+            Assert.IsFalse (string_v.IsStrictEqual (undef_v));
+            Assert.IsFalse (string_v.IsEqual (null_v));
+            Assert.IsFalse (string_v.IsStrictEqual (null_v));
+            Assert.IsTrue (string_v.IsEqual (number_v));
+            Assert.IsFalse (string_v.IsStrictEqual (number_v));
+            Assert.IsTrue (string_v.IsEqual (bool_v));
+            Assert.IsFalse (string_v.IsStrictEqual (bool_v));
+            Assert.IsTrue (string_v.IsEqual (string_v));
+            Assert.IsTrue (string_v.IsStrictEqual (string_v));
+        }
+
+        [Test]
+        public void FromJsonNumber ()
+        {
+            var a = JSValue.FromJson (context, "4.5");
+            var b = JSValue.FromJson (context, "-200");
+            var c = JSValue.FromJson (context, "0");
+            var d = JSValue.FromJson (context, "2e5");
+
+            Assert.IsTrue (a.IsNumber);
+            Assert.IsTrue (b.IsNumber);
+            Assert.IsTrue (c.IsNumber);
+            Assert.IsTrue (d.IsNumber);
+
+            Assert.AreEqual (4.5, a.NumberValue);
+            Assert.AreEqual (-200, b.NumberValue);
+            Assert.AreEqual (0, c.NumberValue);
+            Assert.AreEqual (2e5, d.NumberValue);
+        }
+
+        [Test]
+        public void FromJsonBoolean ()
+        {
+            var a = JSValue.FromJson (context, "false");
+            var b = JSValue.FromJson (context, "true");
+
+            Assert.IsTrue (a.IsBoolean);
+            Assert.IsTrue (b.IsBoolean);
+
+            Assert.AreEqual (false, a.BooleanValue);
+            Assert.AreEqual (true, b.BooleanValue);
+        }
+
+        [Test]
+        public void FromJsonString ()
+        {
+            var a = JSValue.FromJson (context, "\"hello\"");
+            Assert.IsTrue (a.IsString);
+            Assert.AreEqual ("hello", a.StringValue);
+        }
+
+        [Test]
+        public void FromJsonObject ()
+        {
+            Assert.IsTrue (JSValue.FromJson (context, "{}").IsObject);
+        }
+
+        [Test]
+        [ExpectedException (typeof (JSException))]
+        public void InvalidJson ()
+        {
+            JSValue.FromJson (context, "{x/2");
+        }
+
+        [Test]
+        public void JsonRoundTrip ()
+        {
+            Assert.AreEqual ("[1,2,3]", JSValue.FromJson (context, "[1,2,3]").ToJsonString ());
+            Assert.AreEqual ("{\n  \"x\": 4,\n  \"y\": \"z\"\n}",
+                JSValue.FromJson (context, "{\"x\":4,\"y\":\"z\"}").ToJsonString (2));
+        }
+
+        [Test]
+        public void ProtectUnprotect ()
+        {
+            var a = new JSValue (context, 5);
+            a.Protect ();
+            a.Unprotect ();
+        }
+    }
+}
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]