Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Unit tests for Upshot</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<link href="css/qunit.css" rel="stylesheet" type="text/css" />
<link href="css/tests.css" rel="stylesheet" type="text/css" />
<script src="_Scripts/qunit/qunit.js" type="text/javascript"></script>
<script src="_Scripts/jquery/jquery-1.6.2.js" type="text/javascript"></script>
<script src="_Scripts/jquery/jquery.customfunctions.js" type="text/javascript"></script>
<!-- jquery.ui requirements for upshot.dataview.js -->
<script src="_Scripts/jquery/jquery.ui.widget.js" type="text/javascript"></script>
<script src="_Scripts/jquery/jquery.ui.observable.js" type="text/javascript"></script>
<script src="_Scripts/jquery/jquery.ui.dataview.js" type="text/javascript"></script>
<script src="_Scripts/knockout/knockout-2.0.0.js" type="text/javascript"></script>
<script src="_Scripts/upshot/upshot.js" type="text/javascript"></script>
<!-- Knockout compat is loaded before jQueryUI so it's not the default -->
<script src="_Scripts/upshot/Upshot.Compat.Knockout.js" type="text/javascript"></script>
<script src="_Scripts/upshot/Upshot.Compat.jQueryUI.js" type="text/javascript"></script>
<script src="_Scripts/upshot/upshot.dataview.js" type="text/javascript"></script>
<!-- Prepare test bed -->
<script src="Scripts/TestSetup.js" type="text/javascript"></script>
<script src="upshot/Init.js" type="text/javascript"></script>
</head>
<body>
<h2 id="qunit-banner">
</h2>
<h1>Unit Tests</h1>
<div class="test-results">
<div id="qunit-testrunner-toolbar">
</div>
<h2 id="qunit-userAgent">
</h2>
<ol id="qunit-tests">
</ol>
<div id="qunit-fixture">
test markup, will be hidden</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SPA.Test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft IT")]
[assembly: AssemblyProduct("SPA.Test")]
[assembly: AssemblyCopyright("Copyright © Microsoft IT 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("eec1a4da-c756-420c-8d83-c4a82fd490ab")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),Runtime.sln))\tools\WebStack.settings.targets" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{7B8601F8-8D1F-4B9C-8C20-772B673A2FA6}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SPA.Test</RootNamespace>
<AssemblyName>SPA.Test</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<UseIISExpress>false</UseIISExpress>
<SrcOutputPath>$(OutputPath)</SrcOutputPath>
<OutputPath>$(OutputPath)\Test\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Core" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" />
</ItemGroup>
<ItemGroup>
<Content Include="css\qunit.css" />
<Content Include="css\tests.css" />
<Content Include="Index.html" />
<Content Include="Scripts\IntellisenseFix.js" />
<Content Include="Scripts\References.js" />
<Content Include="Scripts\TestSetup.js" />
<Content Include="upshot\ChangeTracking.tests.js" />
<Content Include="upshot\Consistency.tests.js" />
<Content Include="upshot\Core.tests.js" />
<Content Include="upshot\DataContext.tests.js" />
<Content Include="upshot\DataProvider.tests.js" />
<Content Include="upshot\Datasets.js" />
<Content Include="upshot\DataSource.Common.js" />
<Content Include="upshot\DataSource.Tests.js" />
<Content Include="upshot\Delete.Tests.js" />
<Content Include="upshot\EntitySet.tests.js" />
<Content Include="upshot\Init.js" />
<Content Include="upshot\jQuery.DataView.Tests.js" />
<Content Include="upshot\Mapping.tests.js" />
<Content Include="upshot\RecordSet.js" />
<Content Include="Web.config" />
<Content Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</Content>
<Content Include="Web.Release.config">
<DependentUpon>Web.config</DependentUpon>
</Content>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\SPA\SPA.csproj">
<Project>{1ACEF677-B6A0-4680-A076-7893DE176D6B}</Project>
<Name>SPA</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>False</UseIIS>
<AutoAssignPort>False</AutoAssignPort>
<DevelopmentServerPort>34597</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>
</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<Target Name="AfterBuild">
<ItemGroup>
<SpaFiles Include="$(SrcOutputPath)\upshot.js" />
<SpaFiles Include="$(SrcOutputPath)\Upshot.Compat.Knockout.js" />
<SpaFiles Include="$(SrcOutputPath)\Upshot.Compat.jQueryUI.js" />
<SpaFiles Include="$(SrcOutputPath)\upshot.dataview.js" />
</ItemGroup>
<Copy SourceFiles="@(SpaFiles)" DestinationFolder="_Scripts\upshot" />
</Target>
<Target Name="AfterClean">
<ItemGroup>
<SpaFiles Include="_Scripts\upshot\*" />
</ItemGroup>
<Delete Files="@(SpaFiles)" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,32 @@
// These changes remove Intellisense "Function expected" or "Object expected" messages due to
// code that relies on running in the browser. Simply include a reference in
// before QUnit or jQuery like so: /// <reference path="{path}/IntellisenseFix.js" />
// There is no need to include this in the actual html page
//QUnit fixes
(function () {
var test = document.getElementById("");
if (test && !test.style) {
var oldGet = document.getElementById;
document.getElementById = function (id) {
var el = oldGet(id);
el.style = el.getAttribute("style");
return el;
};
}
if (window.location && !window.location.search) {
window.location.search = "";
}
})();
//jQuery fixes 1.6.1
(function () {
if (!document.documentElement.childNodes[0]) {
document.documentElement.childNodes = [{ nodeType: null}];
}
if (!location.href) {
location.href = "";
}
})();

View File

@@ -0,0 +1,20 @@
/// <reference path="IntellisenseFix.js" />
/// <reference path="qunit/qunit.js" />
/// <reference path="SharedScripts/jquery-1.6.2.js" />
/// <reference path="SharedScripts/jquery.tmpl.js" />
/// <reference path="SharedScripts/jquery.ui.observable.js" />
/// <reference path="SharedScripts/jquery.datalink.js" />
/// <reference path="SharedScripts/jquery.customfunctions.js" />
/// <reference path="UpshotScripts/upshot.js" />
/// <reference path="UpshotScripts/Upshot.Compat.Knockout.js" />
/// <reference path="UpshotScripts/Upshot.Compat.jQueryUI.js" />
/// <reference path="UpshotScripts/Upshot.Compat.JsViews.js" />
/// <reference path="SharedScripts/jquery-ui.js" />
/// <reference path="SharedScripts/jquery.render.js" />
/// <reference path="SharedScripts/jquery.views.js" />
/// <reference path="SharedScripts/jquery.list.js" />
/// <reference path="SharedScripts/knockout-2.0.0.debug.js" />
/// <reference path="TestSetup.js" />
// This file enables VS IntelliSense in JavaScript, otherwise it can be removed

View File

@@ -0,0 +1,320 @@
/// <reference path="../../Scripts/References.js" />
if (window.sessionStorage) {
window.sessionStorage.clear();
}
module("DataSource Setup");
var defaultTestTimeout = 10000,
retryLimit = 10;
QUnit.config.testTimeout = defaultTestTimeout;
var testHelper = {
isChrome: /chrome/.test(navigator.userAgent.toLowerCase()),
isFirefox: /mozilla/.test(navigator.userAgent.toLowerCase()) && (!/(compatible|webkit)/.test(navigator.userAgent.toLowerCase())),
initService: function (url, typeOrOptions) {
QUnit.ok(true, "start Init service:" + url + ", time: " + new Date().toLocaleString());
QUnit.config.testTimeout = 120 * 1000;
stop();
var beat = setInterval(function () {
if (window.TestSwarm && window.TestSwarm.heartbeat) {
window.TestSwarm.heartbeat();
}
}, 1000);
testHelper.setCookie("dbi", null, -1);
var options;
if (typeof(typeOrOptions) === "string") {
options = { type: typeOrOptions };
} else {
options = typeOrOptions;
}
testHelper.serviceCall(url, options, 0);
},
serviceCall: function (url, options, retried, beat) {
jQuery.ajax(url, options).then(function () {
QUnit.config.testTimeout = defaultTestTimeout;
clearInterval(beat);
QUnit.ok(true, "Service request succeeded, tried: " + (retried + 1) + " times, timestamp:" + new Date().toLocaleString());
start();
}, function () {
QUnit.ok(true, "Service request failed, retrying " + (retryLimit - retried - 1) + " more times, timestamp:" + new Date().toLocaleString());
setTimeout(function () {
retried++;
if (retried < retryLimit) {
testHelper.serviceCall(url, options, retried);
} else {
// Fail the rest quickly
QUnit.ok(false, "Service call to " + url + " failed");
QUnit.config.testTimeout = 100;
clearInterval(beat);
start();
}
}, 1000);
})
},
setCookie: function (name, value, days) {
if (days) { var date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); var expires = "; expires=" + date.toGMTString(); } else var expires = ""; document.cookie = name + "=" + value + expires + "; path=/";
},
startOnPageSetupComplete: function (url) {
stop();
jQuery("#testFrame").one("load", function () {
// make $ reference the jQuery in the iframe, intentionally global for tests to use
var testFrame = window.frames[0];
$ = testFrame.jQuery;
//Wait for the page to trigger complete
$(testFrame).one("PageSetupComplete", function () {
start()
});
});
jQuery("#testFrame").attr("src", url);
},
startOnPageLoad: function (url, cond) {
stop();
jQuery("#testFrame").one("load", function () {
// make $ reference the jQuery in the iframe, intentionally global for tests to use
var testFrame = window.frames[0];
$ = testFrame.jQuery;
testFrame.alert = function (error) { ok(false, "'alert(" + error + ")' called, failing test"); };
if (cond) {
var checkCond = function () {
if (cond()) {
start();
} else {
setTimeout(function () { checkCond(); }, 200);
}
}
checkCond();
} else {
start();
}
});
jQuery("#testFrame").attr("src", url);
},
wrapFunctions: function (functionNames, triggerName) {
// Allow string or array of strings to be passed
functionNames = $.isArray(functionNames) ? functionNames : [functionNames];
$.each(functionNames, function (index, functionName) {
// Only allow one wrapping per function
if ($.fn[functionName].__oldFunction__) {
testHelper.unwrapFunctions([functionName]);
}
var newFunction = function () {
// Create trigger arguments with function's name that was wrapped
var returnedArgs = [functionName].concat(Array.prototype.slice.call(arguments, 0)),
returnValue = newFunction.__oldFunction__.apply(this, arguments);
// trigger after applying to allow state to be checked in callback
$(this).trigger(triggerName, returnedArgs);
// return the results so wrapped function behaves the same
return returnValue;
};
// Store the new function on the old one
newFunction.__oldFunction__ = $.fn[functionName];
$.fn[functionName] = newFunction;
});
return function () {
//do cleanup
testHelper.unwrapFunctions(functionNames);
};
},
unwrapFunctions: function (functionNames) {
$.each(functionNames, function (index, name) {
$.fn[name] = $.fn[name].__oldFunction__;
});
},
curryStartOnPageLoad: function (url) {
// Return a function with url already set, helpful for passing a callback to a module
return function () {
stop();
jQuery("#testFrame").one("load", function () {
// make $ reference the jQuery in the iframe, intentionally global for tests to use
window.$ = window.frames[0].jQuery;
// TODO: Fix this workaround for page load being too slow to load a new one every test function
// especially slow when debugging
setTimeout(QUnit.start, 100);
});
jQuery("#testFrame").attr("src", url);
}
},
curryPost: function (url) {
return function () {
QUnit.stop();
//REVIEW: This should be an implementation detail of DataSource / DomainSerivceProxy
jQuery.post(url, function () {
QUnit.start();
}, "json");
}
},
setLatency: function (url, queryDelay, cudDelay, success) {
jQuery.ajax({
type: "POST",
url: url + "/SetLatency",
data: '{"queryDelay":' + queryDelay + ',"cudDelay":' + cudDelay + '}',
dataType: "json",
contentType: "application/json",
success: function () {
success();
},
error: function () {
ok(false, "setLatency request failed");
start();
}
});
},
wrapOrAddFunction: function (baseObject, functionName, options) {
// This function either:
// 1) replaces the existing function making callbacks before and after the function would have been invoked
// 2) creates the function making callbacks before and after the function would have been invoked
// If the function existed it will be called as if it were not replaced
// After the function is invoked once it will be reverted back to its original state unless
// revertToOriginal: false is given via the options parameter
// The original function is the return value which allows for the function to be reverted at any time (not after a single callback as usual)
var before = options.before,
after = options.after,
revertToOriginal = options.revertToOriginal !== false, // Default to true when unsupplied
backupOfOriginalFunction;
// If function exists back it up
if (baseObject[functionName]) {
backupOfOriginalFunction = baseObject[functionName];
}
// Overwrite or create function
baseObject[functionName] = function () {
// Revert to original method, revertToOriginal is true by default
if (revertToOriginal) {
if (backupOfOriginalFunction) {
baseObject[functionName] = backupOfOriginalFunction;
} else {
// If there was no original function remove the one added by wrapOrAddFunction
delete baseObject[functionName];
}
}
if (before) {
before.apply(this, Array.prototype.slice.call(arguments));
}
if (backupOfOriginalFunction) {
backupOfOriginalFunction.apply(this, Array.prototype.slice.call(arguments));
}
if (after) {
after.apply(this, Array.prototype.slice.call(arguments));
}
}
// Allows one to revert to original state in their own code when revertToOriginal is false
return backupOfOriginalFunction;
},
whenCondition: function (callback, interval, timeout) {
var retry,
deferred = $.Deferred();
interval = interval || 500;
timeout = timeout || QUnit.config.testTimeout;
retry = timeout / interval;
if (!callback()) {
var pollCallback = function () {
if (!callback()) {
--retry;
if (retry > 0) {
setTimeout(pollCallback, interval);
} else {
deferred.reject();
}
} else {
deferred.resolve();
}
};
setTimeout(pollCallback, interval);
} else {
deferred.resolve();
}
return deferred.promise();
},
startOnCondition: function (callback, interval, timeout) {
var retry;
interval = interval || 500;
timeout = timeout || QUnit.config.testTimeout;
retry = timeout / interval;
stop();
testHelper.whenCondition(callback, interval)
.then(start);
},
changeValueAndWait: function (selector, value, delay) {
stop();
var input = $(selector);
if (input.length !== 1) {
throw "Only support one input";
}
var test = function () {
input.unbind("change", test);
setTimeout(function () { start(); }, delay ? delay : 100);
}
input.one("change", test).focusin().val(value).focusout().trigger("change");
},
// this will allow one-time ajax mock.
mockAjaxOnce: function (url, result, statusText, error) {
if ($.ajax._simulatedurl) {
throw "cannot simulate ajax concurrently (prev=" + $.ajax._simulatedurl + ")";
}
var $ajax = $.ajax;
$.ajax = function (settings) {
if (settings.url.indexOf(url) == 0) {
// revert $.ajax to orginal
$.ajax = $ajax;
var deferred = $.Deferred();
setTimeout(function () {
// this follows $.ajax().fail() and $.ajax().done() signature
if (statusText) {
if (settings.error) {
settings.error.apply(null, [{ responseText: statusText, status: 200 }, statusText, error]);
}
deferred.reject(undefined, statusText, error);
} else {
if (settings.type === "POST") {
var data = JSON.parse(settings.data);
var ret = result || {
SubmitChangesResult: [{ Entity: data.changeSet[0].Entity}]
};
if (settings.success) {
settings.success.apply(null, [ret, "statusText", { status: 200}]);
}
deferred.resolve(ret);
} else {
var ret = result || {
EmptyResult: {
RootResults: [],
Metadata: [{ type: "dummy"}]
}
};
if (settings.success) {
settings.success.apply(null, [ret]);
}
deferred.resolve(ret);
}
}
}, 10);
return deferred.promise();
} else {
return $ajax(settings);
}
}
$.ajax._simulatedurl = url;
$.ajax._$ajax = $ajax;
},
unmockAjax: function () {
if ($.ajax._$ajax) {
$.ajax = $.ajax._$ajax;
}
}
};

View File

@@ -0,0 +1,30 @@
<?xml version="1.0"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
In the example below, the "SetAttributes" transform will change the value of
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
finds an atrribute "name" that has a value of "MyDB".
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
-->
<system.web>
<!--
In the example below, the "Replace" transform will replace the entire
<customErrors> section of your web.config file.
Note that because there is only one customErrors section under the
<system.web> node, there is no need to use the "xdt:Locator" attribute.
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
</configuration>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
In the example below, the "SetAttributes" transform will change the value of
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
finds an atrribute "name" that has a value of "MyDB".
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
-->
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<!--
In the example below, the "Replace" transform will replace the entire
<customErrors> section of your web.config file.
Note that because there is only one customErrors section under the
<system.web> node, there is no need to use the "xdt:Locator" attribute.
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
</configuration>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
</configuration>

View File

@@ -0,0 +1,226 @@
/**
* QUnit 1.2.0pre - A JavaScript Unit Testing Framework
*
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2011 John Resig, Jörn Zaefferer
* Dual licensed under the MIT (MIT-LICENSE.txt)
* or GPL (GPL-LICENSE.txt) licenses.
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 15px 15px 0 0;
-moz-border-radius: 15px 15px 0 0;
-webkit-border-top-right-radius: 15px;
-webkit-border-top-left-radius: 15px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 15px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
box-shadow: inset 0px 2px 13px #999;
-moz-box-shadow: inset 0px 2px 13px #999;
-webkit-box-shadow: inset 0px 2px 13px #999;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
margin: 0.5em;
padding: 0.4em 0.5em 0.4em 0.5em;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #5E740B;
background-color: #fff;
border-left: 26px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 26px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 15px 15px;
-moz-border-radius: 0 0 15px 15px;
-webkit-border-bottom-right-radius: 15px;
-webkit-border-bottom-left-radius: 15px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
}

View File

@@ -0,0 +1,15 @@
body
{
padding: 0px;
margin: 0px;
}
h1
{
margin: 5px;
}
div.test-results
{
width: 500px;
height: 700px;
margin:5px;
}

View File

@@ -0,0 +1,348 @@
/// <reference path="../Scripts/References.js" />
(function (upshot, ko, undefined) {
module("ChangeTracking");
var observability = upshot.observability;
test("Explicit commit multiple property edits", 5, function () {
var submitCount = 0;
var propertyChangedCount = 0;
var dc = createTestContext(function () {
submitCount++;
}, true);
var entitySet = dc.getEntitySet("Product");
var prod = entitySet.getEntities()[0];
var state = entitySet.getEntityState(prod);
equal(state, upshot.EntityState.Unmodified);
entitySet.bind("propertyChanged", function () {
propertyChangedCount++;
});
$.observable(prod).property("Name", "xyz");
$.observable(prod).property("Name", "foo");
$.observable(prod).property("Price", 9.99);
equal(propertyChangedCount, 3);
state = entitySet.getEntityState(prod);
equal(state, upshot.EntityState.ClientUpdated);
equal(submitCount, 0);
dc.commitChanges();
equal(submitCount, 1);
});
asyncTest("Implicit commit multiple property edits", 5, function () {
var submitCount = 0;
var propertyChangedCount = 0;
var dc = createTestContext(function () {
submitCount++;
}, false);
var entitySet = dc.getEntitySet("Product");
var prod = entitySet.getEntities()[0];
var state = entitySet.getEntityState(prod);
equal(state, upshot.EntityState.Unmodified);
entitySet.bind("propertyChanged", function () {
propertyChangedCount++;
});
$.observable(prod).property("Name", "xyz");
$.observable(prod).property("Name", "foo");
$.observable(prod).property("Price", 9.99);
// before the timeout has expired we shouldn't have committed anything
equal(submitCount, 0);
equal(propertyChangedCount, 3);
state = entitySet.getEntityState(prod);
equal(state, upshot.EntityState.ClientUpdated);
// Here we queue the test verification and start so that it runs
// AFTER the queued commit
setTimeout(function () {
equal(submitCount, 1);
start();
}, 0);
});
asyncTest("Implicit commit multiple array operations", 5, function () {
var submitCount = 0;
var dc = createTestContext(function (options, editedEntities) {
submitCount++;
equal(editedEntities.length, 2);
}, false);
var entitySet = dc.getEntitySet("Product");
var prod = entitySet.getEntities()[0];
// do an insert
var newProd = {
ID: 2,
Name: "Frish Gnarbles",
Category: "Snacks",
Price: 7.99
};
$.observable(entitySet.getEntities()).insert(newProd);
var state = entitySet.getEntityState(newProd);
equal(state, upshot.EntityState.ClientAdded);
// do a delete
entitySet.deleteEntity(prod);
state = entitySet.getEntityState(prod);
equal(state, upshot.EntityState.ClientDeleted);
// before the timeout has expired we shouldn't have committed anything
equal(submitCount, 0);
// Here we queue the test verification and start so that it runs
// AFTER the queued commit
setTimeout(function () {
equal(submitCount, 1);
start();
}, 0);
});
/* TODO: We forced managed associations on for Dev11 beta, since unmanaged associations are broken.
test("Nested entities can be added to an entity, and navigation properties are untracked", 16, function () {
try {
upshot.observability.configuration = observability.knockout;
var manageAssociations = false;
var dc = createKoTestContext(function () { }, false, manageAssociations);
var orders = dc.getEntitySet("Order"),
orderDetails = dc.getEntitySet("OrderDetail"),
order = orders.getEntities()()[0],
order2 = orders.getEntities()()[1],
orderDetail = orderDetails.getEntities()()[0];
order.OrderDetails.remove(orderDetail);
equal(1, order.OrderDetails().length, "There should only be a single order detail");
equal(upshot.EntityState.Unmodified, orders.getEntityState(order), "The order should not be modified");
equal(upshot.EntityState.Unmodified, orderDetails.getEntityState(orderDetail), "The order detail should not be modified");
order.OrderDetails.push(orderDetail);
equal(2, order.OrderDetails().length, "There should be two order details");
equal(upshot.EntityState.Unmodified, orders.getEntityState(order), "The order should not be modified");
equal(upshot.EntityState.Unmodified, orderDetails.getEntityState(orderDetail), "The order detail should not be modified");
orderDetail.Order(order2);
equal(orderDetail.OrderId(), order2.Id(), "Ids should be equal");
equal(upshot.EntityState.Unmodified, orders.getEntityState(order2), "The order should not be modified");
equal(upshot.EntityState.ClientUpdated, orderDetails.getEntityState(orderDetail), "The order detail should not be modified");
equal(true, orderDetails.isUpdated(orderDetail, "OrderId"), "The OrderId should be modified");
equal(false, orderDetails.isUpdated(orderDetail, "Order"), "The Order should not be tracked");
var properties = [];
$.each(observability.knockout.unmap(orderDetail, "OrderDetail"), function (key, value) {
properties.push(key);
equal(ko.utils.unwrapObservable(orderDetail[key]), value, "Properties should be equal");
});
equal(properties.length, 4, "The should be 4 serialized properties");
} finally {
upshot.observability.configuration = observability.jquery;
}
});
*/
test("Nested entities can be added to an entity, and navigation properties are computed", 39, function () {
try {
upshot.observability.configuration = observability.knockout;
var dc = createKoTestContext(function () { }, false);
var orders = dc.getEntitySet("Order"),
orderDetails = dc.getEntitySet("OrderDetail"),
order = orders.getEntities()()[0],
order2 = orders.getEntities()()[1],
orderDetail = orderDetails.getEntities()()[0];
ok(order.OrderDetails.indexOf(orderDetail) >= 0 && order2.OrderDetails.indexOf(orderDetail) < 0 && orderDetail.Order() === order, "The order detail is a child of order1");
equal(orders.getEntityState(order), upshot.EntityState.Unmodified, "order1 should not be modified");
equal(orders.getEntityState(order2), upshot.EntityState.Unmodified, "order2 should not be modified");
equal(orderDetails.getEntityState(orderDetail), upshot.EntityState.Unmodified, "The order detail should not be modified");
equal(orderDetails.isUpdated(orderDetail, "OrderId"), false, "The OrderId should not be modified");
equal(orderDetails.isUpdated(orderDetail, "Order"), false, "The Order should not be tracked");
orderDetail.OrderId(order2.Id());
ok(order2.OrderDetails.indexOf(orderDetail) >= 0 && order.OrderDetails.indexOf(orderDetail) < 0 && orderDetail.Order() === order2, "The order detail is a child of order2");
equal(orders.getEntityState(order), upshot.EntityState.Unmodified, "order1 should not be modified");
equal(orders.getEntityState(order2), upshot.EntityState.Unmodified, "order2 should not be modified");
equal(orderDetails.getEntityState(orderDetail), upshot.EntityState.ClientUpdated, "The order detail should be ClientUpdated");
equal(orderDetails.isUpdated(orderDetail, "OrderId"), true, "The OrderId should be modified");
equal(orderDetails.isUpdated(orderDetail, "Order"), false, "The Order should not be tracked");
orderDetails.revertUpdates(orderDetail);
ok(order.OrderDetails.indexOf(orderDetail) >= 0 && order2.OrderDetails.indexOf(orderDetail) < 0 && orderDetail.Order() === order, "The order detail is a child of order1");
equal(orders.getEntityState(order), upshot.EntityState.Unmodified, "order1 should not be modified");
equal(orders.getEntityState(order2), upshot.EntityState.Unmodified, "order2 should not be modified");
equal(orderDetails.getEntityState(orderDetail), upshot.EntityState.Unmodified, "The order detail should not be modified");
equal(orderDetails.isUpdated(orderDetail, "OrderId"), false, "The OrderId should not be modified");
equal(orderDetails.isUpdated(orderDetail, "Order"), false, "The Order should not be tracked");
orderDetail.Order(order2);
ok(orderDetail.OrderId() === order2.Id(), "Ids should be equal");
equal(orders.getEntityState(order2), upshot.EntityState.Unmodified, "The order should not be modified");
equal(orderDetails.getEntityState(orderDetail), upshot.EntityState.ClientUpdated, "The order detail should be ClientUpdated");
equal(orderDetails.isUpdated(orderDetail, "OrderId"), true, "The OrderId should be modified");
equal(orderDetails.isUpdated(orderDetail, "Order"), false, "The Order should not be tracked");
orderDetails.revertUpdates(orderDetail);
ok(order.OrderDetails.indexOf(orderDetail) >= 0 && order2.OrderDetails.indexOf(orderDetail) < 0 && orderDetail.Order() === order, "The order detail is a child of order1");
equal(orders.getEntityState(order), upshot.EntityState.Unmodified, "order1 should not be modified");
equal(orders.getEntityState(order2), upshot.EntityState.Unmodified, "order2 should not be modified");
equal(orderDetails.getEntityState(orderDetail), upshot.EntityState.Unmodified, "The order detail should not be modified");
equal(orderDetails.isUpdated(orderDetail, "OrderId"), false, "The OrderId should not be modified");
equal(orderDetails.isUpdated(orderDetail, "Order"), false, "The Order should not be tracked");
orderDetail.Order(null);
equal(orderDetail.OrderId(), null, "FK should be null");
equal(orders.getEntityState(order), upshot.EntityState.Unmodified, "The old order should not be modified");
equal(orderDetails.getEntityState(orderDetail), upshot.EntityState.ClientUpdated, "The order detail should be ClientUpdated");
equal(orderDetails.isUpdated(orderDetail, "OrderId"), true, "The OrderId should be modified");
equal(orderDetails.isUpdated(orderDetail, "Order"), false, "The Order should not be tracked");
var properties = [];
$.each(observability.knockout.unmap(orderDetail, "OrderDetail"), function (key, value) {
properties.push(key);
equal(ko.utils.unwrapObservable(orderDetail[key]), value, "Properties should be equal");
});
equal(properties.length, 4, "The should be 4 serialized properties");
} finally {
upshot.observability.configuration = observability.jquery;
}
});
test("Nested entities can be added to an entity, and property changes do not bubble to the parent", 2, function () {
try {
upshot.observability.configuration = observability.knockout;
var dc = createKoTestContext(function () { }, false);
var orders = dc.getEntitySet("Order"),
orderDetails = dc.getEntitySet("OrderDetail"),
order = orders.getEntities()()[0],
orderDetail = orderDetails.getEntities()()[0];
orderDetail.Name("asdf");
equal(orders.getEntityState(order), upshot.EntityState.Unmodified, "The order should not be modified");
equal(orderDetails.getEntityState(orderDetail), upshot.EntityState.ClientUpdated, "The order detail should not be modified");
} finally {
upshot.observability.configuration = observability.jquery;
}
});
// Create and return a context using the specified submitChanges mock
function createTestContext(submitChangesMock, bufferChanges) {
var dataProvider = new upshot.DataProvider();
var implicitCommitHandler;
if (!bufferChanges) {
implicitCommitHandler = function () {
dc._commitChanges({ providerParameters: {} });
}
}
var dc = new upshot.DataContext(dataProvider, implicitCommitHandler);
dc._submitChanges = submitChangesMock;
// add a single product to the context
var type = "Product";
var products = [];
products.push({
ID: 1,
Name: "Crispy Snarfs",
Category: "Snacks",
Price: 12.99
});
products.push({
ID: 2,
Name: "Cheezy Snax",
Category: "Snacks",
Price: 1.99
});
// mock out enough metadata to do the attach
upshot.metadata(type, { key: ["ID"] });
dc.merge(products, type, null);
return dc;
}
function createKoTestContext(submitChangesMock, bufferChanges) {
var dataProvider = new upshot.DataProvider();
var implicitCommitHandler;
if (!bufferChanges) {
implicitCommitHandler = function () {
dc._commitChanges({ providerParameters: {} });
}
}
var dc = new upshot.DataContext(dataProvider, implicitCommitHandler);
dc._submitChanges = submitChangesMock;
// add a single product to the context
var manageAssociations = true; // TODO: Lift this to a createKoTestContext parameter when unmanaged associations is supported.
var OrderDetail = function (data) {
this.Id = ko.observable(data.Id);
this.Name = ko.observable(data.Name);
this.Order = ko.observable();
this.OrderId = manageAssociations ? ko.observable(data.OrderId) : ko.computed(function () {
return this.Order() ? this.Order().Id() : data.OrderId;
}, this);
this.Extra = ko.observable("extra");
};
var Order = function (data) {
this.Id = ko.observable(data.Id);
this.Name = ko.observable(data.Name);
this.OrderDetails = ko.observableArray(ko.utils.arrayMap(data.OrderDetails, function (od) { return new OrderDetail(od); }));
this.Extra = ko.observable("extra");
};
var orders = [],
order = {
Id: 1,
Name: "Order 1",
OrderDetails: []
};
orders.push(new Order(order));
orders.push(new Order({
Id: 2,
Name: "Order 2",
OrderDetails: []
}));
var orderDetails = [];
orderDetails.push(new OrderDetail({
Id: 1,
Name: "Order Detail 1",
OrderId: order.Id
}));
orderDetails.push(new OrderDetail({
Id: 2,
Name: "Order Detail 2",
OrderId: order.Id
}));
orders[0].OrderDetails(orderDetails);
// mock out enough metadata to do the attach
upshot.metadata("Order", { key: ["Id"], fields: { Id: { type: "Int32:#System" }, Name: { type: "String:#System" }, OrderDetails: { type: "OrderDetail", association: { Name: "O_OD", isForeignKey: false, thisKey: ["Id"], otherKey: ["OrderId"] }, array: true } } });
upshot.metadata("OrderDetail", { key: ["Id"], fields: { Id: { type: "Int32:#System" }, Name: { type: "String:#System" }, Order: { type: "Order", association: { Name: "O_OD", isForeignKey: true, thisKey: ["OrderId"], otherKey: ["Id"]} }, OrderId: { type: "Int32:#System"}} });
dc.merge(orders, "Order", null);
return dc;
}
})(upshot, ko);

View File

@@ -0,0 +1,158 @@
/// <reference path="../Scripts/References.js" />
(function (global, upshot, undefined) {
module("Consistency.tests.js");
function getEntitySet() {
upshot.metadata("Employee", {
key: ["Id"],
fields: {
Name: {
type: "String:#System"
},
Manager: {
type: "Employee",
association: {
name: "Employee_Employee",
thisKey: ["ManagerId"],
otherKey: ["Id"],
isForeignKey: true
}
},
Reports: {
type: "Employee",
array: true,
association: {
name: "Employee_Employee2",
thisKey: ["Id"],
otherKey: ["ManagerId"],
isForeignKey: false
}
},
Id: {
type: "Int32:#System"
},
ManagerId: {
type: "Int32:#System"
}
}
});
var context = new upshot.DataContext();
context.merge([
{ Id:1, Name: "Fred", ManagerId: 2 },
{ Id:2, Name: "Bob" },
{ Id:3, Name: "Jane" }
], "Employee");
return context.getEntitySet("Employee");
}
test("AssociatedEntitiesView wrt FK update and revert", 6, function () {
var entitySet = getEntitySet(),
entities = entitySet.getEntities();
ok(entities[1].Reports.length === 1, "Bob should have Fred as a report");
ok(entities[2].Reports.length === 0, "Jane has no reports");
$.observable(entities[0]).property("ManagerId", 3);
ok(entities[1].Reports.length === 0, "Bob should have no reports");
ok(entities[2].Reports.length === 1, "Jane should have Fred as a report");
entitySet.revertChanges();
ok(entities[1].Reports.length === 1, "Bob should have Fred as a report");
ok(entities[2].Reports.length === 0, "Jane has no reports");
});
test("AssociatedEntitiesView wrt insert and revert", 3, function () {
var entitySet = getEntitySet(),
entities = entitySet.getEntities();
ok(entities[1].Reports.length === 1, "Bob should have Fred as a report");
$.observable(entities[1].Reports).insert(entities[2]);
ok(entities[1].Reports.length === 2, "Bob should have Fred and Jane as reports");
entitySet.revertChanges();
ok(entities[1].Reports.length === 1, "Bob should have Fred as a report");
});
test("LocalDataSource auto-refresh over AssociatedEntitiesView", 9, function () {
stop();
var entitySet = getEntitySet(),
entities = entitySet.getEntities();
ok(entities[1].Reports.length === 1, "Bob should have Fred as a report");
ok(entities[2].Reports.length === 0, "Jane has no reports");
var localDataSource = new upshot.LocalDataSource({
source: entities[1].Reports,
autoRefresh: true,
filter: { property: "Name", operator: "!=", value: "Joan" }
});
localDataSource.refresh(function () {
ok(localDataSource.getEntities().length === 1, "Bob should have Fred as a report");
$.observable(entities[0]).property("ManagerId", 3);
ok(entities[1].Reports.length === 0, "Bob should have no reports");
ok(entities[2].Reports.length === 1, "Jane should have Fred as a report");
ok(localDataSource.getEntities().length === 0, "Bob should have no reports");
entitySet.revertChanges();
ok(entities[1].Reports.length === 1, "Bob should have Fred as a report");
ok(entities[2].Reports.length === 0, "Jane has no reports");
ok(localDataSource.getEntities().length === 1, "Bob should have Fred as a report");
start();
});
});
test("LocalDataSource auto-refresh over EntitySet wrt property updates and revert", 3, function () {
stop();
var entitySet = getEntitySet();
var localDataSource = new upshot.LocalDataSource({
source: entitySet,
autoRefresh: true,
filter: { property: "Name", value: "Fred" }
});
localDataSource.refresh(function () {
ok(localDataSource.getEntities().length === 1, "We have an employee named Fred");
$.observable(localDataSource.getEntities()[0]).property("Name", "Fredrick");
ok(localDataSource.getEntities().length === 0, "We have no employees named Fred");
entitySet.revertChanges();
ok(localDataSource.getEntities().length === 1, "We have an employee named Fred");
start();
});
});
test("EntitySet wrt insert and revert", 4, function () {
var entitySet = getEntitySet();
ok(entitySet.getEntities().length === 3, "Have 3 entities");
var newEmployee = { Name: "Barb" };
$.observable(entitySet.getEntities()).insert(newEmployee);
ok(entitySet.getEntities().length === 4, "Now 4 entities");
entitySet.revertChanges();
ok(entitySet.getEntities().length === 3, "Have 3 entities");
ok((entitySet.getEntityState(newEmployee) || upshot.EntityState.Deleted) === upshot.EntityState.Deleted);
});
})(this, upshot);

View File

@@ -0,0 +1,293 @@

(function(upshot) {
module("Core.js");
var Custom = upshot.defineClass(null);
test("classof utility test", 50, function () {
var testCases = [
[ true, "boolean"],
[ null, "null"],
[ 1, "number"],
[ [], "array"],
[ "s", "string"],
[ {}, "object"],
[ new Custom(), "object" ],
[ Boolean(true), "boolean" ],
[ new Boolean(true), "boolean" ],
[ 1, "number" ],
[ 1.0, "number" ],
[ Number(1), "number" ],
[ new Number(1), "number" ],
[ Number.MAX_VALUE, "number" ],
[ Number.MIN_VALUE, "number" ],
[ Number.NaN, "number" ],
[ Number.NEGATIVE_INFINITY, "number" ],
[ Number.POSITIVE_INFINITY, "number" ],
[ "A", "string" ],
[ String("A"), "string" ],
[ new String("A"), "string" ],
[ new Date(), "date" ],
[ undefined, "undefined" ],
[ function () {}, "function" ],
[ /./, "regexp" ]
];
for(var i = 0; i < testCases.length; i++) {
// verify our classof function
var testPair = testCases[i];
var result = upshot.classof(testPair[0]);
equal(result, testPair[1]);
// verify that we produce the same results as the jQuery function
var jQueryResult = $.type(testPair[0]);
equal(result, jQueryResult);
}
});
test("isArray utility test", 2, function () {
equal(upshot.isArray([]), true);
equal(upshot.isArray(5), false);
});
test("HelloWorldNs test", 2, function () {
equal(typeof upshot.defineNamespace, "function", "pre test");
upshot.defineNamespace("HelloWorldNs");
equal(typeof HelloWorldNs, "object", "HelloWorldNs is defined");
});
test("HelloWorldCls simple test", 4, function () {
var HelloWorldCls = upshot.defineClass(
function(result) {
this.result = result;
},
{
add: function(value) {
this.result += value;
},
subtract: function(value) {
this.result -= value;
}
}
);
equal(typeof HelloWorldCls, "function", "HelloWorldCls is defined");
var val = 5;
var calc = new HelloWorldCls(val);
equal(calc.result, val, "precheck result");
val += 3;
calc.add(3);
equal(calc.result, val, "add check");
val -= 4;
calc.subtract(4);
equal(calc.result, val, "subtract check");
});
test("HelloWorldCls inherit test: prototype inheritance", 2, function () {
var result;
var HelloWorldBase = upshot.defineClass(
function() {
this.id = 1;
},
{
foo: function(val) {
result += this.id + ".HelloWorldBase.foo(" + val + ")";
}
}
);
var HelloWorldCls = upshot.deriveClass(
HelloWorldBase.prototype,
function() {
this.id = 2;
},
{
bar: function(val) {
result += this.id + ".HelloWorldCls.bar(" + val + ")";
}
}
);
var tmp = new HelloWorldCls();
result = "";
tmp.foo("hi");
equal(result, "2.HelloWorldBase.foo(hi)", "test foo");
result = "";
tmp.bar("hey");
equal(result, "2.HelloWorldCls.bar(hey)", "test bar");
});
test("HelloWorldCls inherit test: override ctor", 1, function () {
var result;
var HelloWorldBase = upshot.defineClass(
function(val) {
result += "HelloWorldBase.ctor(" + val + ")";
}
);
var base = HelloWorldBase.prototype,
HelloWorldCls = upshot.deriveClass(
base,
function(val) {
result += "HelloWorldCls.ctor(" + val + ")";
base.constructor.call(this, val);
}
);
result = "";
var tmp = new HelloWorldCls("hey");
equal(result, "HelloWorldCls.ctor(hey)HelloWorldBase.ctor(hey)", "test ctor");
});
test("HelloWorldCls inherit test: override method", 1, function () {
var result;
var HelloWorldBase = upshot.defineClass(
function() {
this.id = 1;
},
{
foo: function(val) {
result += this.id + ".HelloWorldBase.foo(" + val + ")";
}
}
);
var base = HelloWorldBase.prototype,
HelloWorldCls = upshot.deriveClass(
base,
function() {
this.id = 2;
},
{
foo: function(val) {
result += this.id + ".HelloWorldCls.foo(" + val + ")";
base.foo.call(this, val);
}
}
);
var tmp = new HelloWorldCls();
result = "";
tmp.foo("hey");
equal(result, "2.HelloWorldCls.foo(hey)2.HelloWorldBase.foo(hey)", "test foo");
});
test("HelloWorldCls inherit test: multi prototype inheritance", 3, function () {
var result;
var HelloWorldBase = upshot.defineClass(
function() {
this.id = 1;
},
{
foo: function(val) {
result += this.id + ".HelloWorldBase.foo(" + val + ")";
}
}
);
var HelloWorldInt = upshot.deriveClass(
HelloWorldBase.prototype,
function() {
this.id = 2;
},
{
fred: function(val) {
result += this.id + ".HelloWorldInt.fred(" + val + ")";
}
}
);
var HelloWorldCls = upshot.deriveClass(
HelloWorldInt.prototype,
function() {
this.id = 3;
},
{
bar: function(val) {
result += this.id + ".HelloWorldCls.bar(" + val + ")";
}
}
);
var tmp = new HelloWorldCls();
result = "";
tmp.foo("hi");
equal(result, "3.HelloWorldBase.foo(hi)", "test foo");
result = "";
tmp.fred("huh");
equal(result, "3.HelloWorldInt.fred(huh)", "test fred");
result = "";
tmp.bar("hey");
equal(result, "3.HelloWorldCls.bar(hey)", "test bar");
});
test("HelloWorldCls inherit test: multi override ctor", 1, function () {
var result;
var HelloWorldBase = upshot.defineClass(
function(val) {
result += "HelloWorldBase.ctor(" + val + ")";
}
);
var base = HelloWorldBase.prototype,
HelloWorldInt = upshot.deriveClass(
base,
function(val) {
result += "HelloWorldInt.ctor(" + val + ")";
base.constructor.call(this, val);
}
);
var baseInt = HelloWorldInt.prototype,
HelloWorldCls = upshot.deriveClass(
baseInt,
function(val) {
result += "HelloWorldCls.ctor(" + val + ")";
baseInt.constructor.call(this, val);
}
);
result = "";
var tmp = new HelloWorldCls("hey");
equal(result, "HelloWorldCls.ctor(hey)HelloWorldInt.ctor(hey)HelloWorldBase.ctor(hey)", "test ctor");
});
test("HelloWorldCls inherit test: multi override method", 1, function () {
var result;
var HelloWorldBase = upshot.defineClass(
function() {
this.id = 1;
},
{
foo: function(val) {
result += this.id + ".HelloWorldBase.foo(" + val + ")";
}
}
);
var base = HelloWorldBase.prototype,
HelloWorldInt = upshot.deriveClass(
base,
function() {
this.id = 2;
},
{
foo: function(val) {
result += this.id + ".HelloWorldInt.foo(" + val + ")";
base.foo.call(this, val);
}
}
);
var baseInt = HelloWorldInt.prototype,
HelloWorldCls = upshot.deriveClass(
baseInt,
function() {
this.id = 3;
},
{
foo: function(val) {
result += this.id + ".HelloWorldCls.foo(" + val + ")";
baseInt.foo.call(this, val);
}
}
);
var tmp = new HelloWorldCls();
result = "";
tmp.foo("hey");
equal(result, "3.HelloWorldCls.foo(hey)3.HelloWorldInt.foo(hey)3.HelloWorldBase.foo(hey)", "test foo");
});
})(upshot);

View File

@@ -0,0 +1,7 @@
/// <reference path="../Scripts/References.js" />
(function (upshot) {
module("DataContext tests");
})(upshot);

View File

@@ -0,0 +1,156 @@
/// <reference path="../Scripts/References.js" />
(function (global, upshot, undefined) {
module("DataProvider tests");
function getTestProvider(verifyGet, verifySubmit) {
return {
get: function (getParameters, queryParameters, success, error) {
var queryResult = {
entities: [{ ID: 1, Name: "Mathew" }, { ID: 2, Name: "Amy"}],
totalCount: 2
};
if (verifyGet) {
verifyGet(getParameters, queryParameters);
}
success(queryResult);
},
submit: function (submitParameters, changeSet, success, error) {
if (verifySubmit) {
verifySubmit(submitParameters, changeSet);
}
success(changeSet);
}
};
}
function getTestContext() {
var dc = new upshot.DataContext(getTestProvider());
upshot.metadata(getTestMetadata());
return dc;
}
function getTestMetadata() {
return { Contact: { key: ["ID"] } };
}
// Verify an offline type scenario where a DataProvider is used directly and results
// are "offlined" and rehydrated back into the context (metadata and entities)
test("Offline scenario", 4, function () {
// execute a direct query using the dataprovider and simulate
// caching of the results
var provider = getTestProvider();
var cachedEntities;
provider.get({ operationName: "contacts" }, null, function (result) {
cachedEntities = result.entities;
});
equal(2, cachedEntities.length);
// create a new context and load the cached entities into it
var dataContext = getTestContext();
var mergedEntities = dataContext.merge(cachedEntities, "Contact", null);
// verify that after merge, entities are annotated with their type
var entitySet = dataContext.getEntitySet("Contact");
var contact = entitySet.getEntities()[0];
equal(contact.__type, "Contact");
// verify that the "rehydrated" context is fully functional
equal(entitySet.getEntityState(contact), upshot.EntityState.Unmodified);
$.observable(contact).property("Name", "xyz");
equal(entitySet.getEntityState(contact), upshot.EntityState.ClientUpdated);
});
test("Custom data provider", 4, function () {
var verifySubmit = function (submitParameters, changeSet) {
// verify we got the expected changeset
equal(changeSet.length, 1);
equal(changeSet[0].Entity.Name, "foo");
};
var provider = getTestProvider(null, verifySubmit);
// create a datasource using the provider and verify an E2E query + update cycle
var ds = upshot.RemoteDataSource({
providerParameters: { operationName: "contacts" },
entityType: "Contact",
provider: provider,
bufferChanges: true,
refreshSuccess: function (entities) {
equal(entities.length, 2);
// modify an entity
$.observable(entities[0]).property("Name", "foo");
ds.commitChanges(function () {
ok(true);
});
}
});
upshot.metadata(getTestMetadata());
ds.refresh();
});
test("Verify get/submit parameter handling", 15, function () {
var verifySubmit = function (submitParameters, changeSet) {
// verify "outer params" are pushed in
equal(submitParameters.outerA, "outerA");
equal(submitParameters.outerB, "outerB");
// verify submit only params
equal(submitParameters.submitA, "submitA");
equal(submitParameters.submitB, "submitB");
equal(submitParameters.getA, undefined);
equal(submitParameters.getB, undefined);
};
var verifyGet = function (getParameters) {
// verify "outer params" are pushed in
equal(getParameters.outerA, "outerA");
equal(getParameters.outerB, "outerB");
// verify get only params
equal(getParameters.getA, "getA");
equal(getParameters.getB, "getB");
equal(getParameters.submitA, undefined);
equal(getParameters.submitB, undefined);
// verify original provider parameter objects weren't modified
equal(providerParameters.get.url, undefined);
};
var provider = getTestProvider(verifyGet, verifySubmit);
var providerParameters = {
outerA: "outerA",
outerB: "outerB",
get: {
getA: "getA",
getB: "getB"
},
submit: {
submitA: "submitA",
submitB: "submitB"
}
};
var ds = upshot.RemoteDataSource({
providerParameters: providerParameters,
entityType: "Contact",
provider: provider,
bufferChanges: true,
refreshSuccess: function (entities) {
equal(entities.length, 2);
// modify an entity
$.observable(entities[0]).property("Name", "foo");
ds.commitChanges(function () {
ok(true);
});
}
});
upshot.metadata(getTestMetadata());
ds.refresh();
});
})(this, upshot);

View File

@@ -0,0 +1,161 @@
/// <reference path="../Scripts/References.js" />
var dsTestDriver;
(function (global, upshot, undefined) {
if ($.isPlainObject(dsTestDriver)) {
return;
}
function createProductsResult () {
return {
GetProductsResult: {
TotalCount: 3,
RootResults: [
{ ID: 1, Manufacturer: "Canon", Price: 200 },
{ ID: 2, Manufacturer: "Nikon", Price: 400 },
{ ID: 3, Manufacturer: "Pentax", Price: 500 }
],
Metadata: [
{
type: "Product:#Sample.Models",
key: ["ID"],
fields: {
ID: { type: "Int32:#System" },
Manufacturer: { type: "String:#System" },
Price: { type: "Decimal:#System" }
},
rules: {
ID: { required: true },
Price: { range: [0, 1000] }
}
}
]
}
};
}
dsTestDriver = {
ds: null,
simulatedSuccess: true,
errorStatus: "ErrorStatus",
errorValue: "ErrorValue",
validationError: {
SubmitChangesResult: [{
ValidationErrors: [{
Message: "The ID field is required!"
}]
}]
},
simulateSuccessService: function (results) {
testHelper.mockAjaxOnce("unused", this.productsResult = results || createProductsResult());
this.simulatedSuccess = true;
},
simulatePostSuccessService: function (results) {
testHelper.mockAjaxOnce("unused", results);
this.simulatedSuccess = true;
},
simulateErrorService: function () {
testHelper.mockAjaxOnce("unused", null, this.errorStatus, this.errorValue);
this.simulatedSuccess = false;
},
simulateValidationErrorService: function () {
testHelper.mockAjaxOnce("unused", this.validationError);
this.simulatedSuccess = false;
},
onRefreshStartEvent: function (event) {
equal(event.type, "refreshStart", "Event triggered");
var args = Array.prototype.slice.call(arguments);
args.shift();
dsTestDriver.onRefreshStart.apply(this, args);
},
onRefreshStart: function () {
ok(true, "Callback called");
equal(arguments.length, 0, "Argument checked");
ok(this === dsTestDriver.ds, "Context checked");
},
onRefreshSuccessEvent: function (event, entities, totalCount) {
equal(event.type, "refreshSuccess", "Event triggered");
var args = Array.prototype.slice.call(arguments);
args.shift();
dsTestDriver.onRefreshSuccess.apply(this, args);
},
onRefreshSuccess: function (entities, totalCount) {
ok(true, "Callback called");
ok(dsTestDriver.simulatedSuccess, "Simulation checked");
equal(arguments.length, 2, "Argument checked");
ok(this === dsTestDriver.ds, "Context checked");
equal(totalCount, dsTestDriver.productsResult.GetProductsResult.TotalCount, "Count checked");
var lastIndex = dsTestDriver.ds._take || (dsTestDriver.ds.dataSource && dsTestDriver.ds.dataSource._take) || totalCount;
equal(entities[lastIndex - 1].Price, dsTestDriver.productsResult.GetProductsResult.RootResults[lastIndex - 1].Price, "Price checked");
start();
},
onRefreshErrorEvent: function (event) {
equal(event.type, "refreshError", "Event triggered");
var args = Array.prototype.slice.call(arguments);
args.shift();
dsTestDriver.onRefreshError.apply(this, args);
},
onRefreshError: function (httpStatus, errorText, jqXHR) {
ok(true, "Callback called");
ok(!dsTestDriver.simulatedSuccess, "Simulation checked");
equal(arguments.length, 3, "Argument checked");
ok(this === dsTestDriver.ds, "Context checked");
equal(errorText, dsTestDriver.errorValue, "error checked");
start();
},
onCommitStartEvent: function (event) {
equal(event.type, "commitStart", "Event triggered");
var args = Array.prototype.slice.call(arguments);
args.shift();
dsTestDriver.onCommitStart.apply(this, args);
},
onCommitStart: function () {
ok(true, "Callback called");
equal(arguments.length, 0, "Argument checked");
ok(this === dsTestDriver.ds, "Context checked");
},
onCommitSuccessEvent: function (event) {
equal(event.type, "commitSuccess", "Event triggered");
var args = Array.prototype.slice.call(arguments);
args.shift();
dsTestDriver.onCommitSuccess.apply(this, args);
},
onCommitSuccess: function () {
ok(true, "Callback called");
ok(dsTestDriver.simulatedSuccess, "Simulation checked");
equal(arguments.length, 1, "Argument checked");
var submitResults = arguments[0];
equal(submitResults.length, 1, "submitResults checked");
ok(this === dsTestDriver.ds, "Context checked");
start();
},
onCommitErrorEvent: function (event) {
equal(event.type, "commitError", "Event triggered");
var args = Array.prototype.slice.call(arguments);
args.shift();
dsTestDriver.onCommitError.apply(this, args);
},
onCommitError: function (httpStatus, errorText, jqXHR, submitResult) {
ok(true, "Callback called");
ok(!dsTestDriver.simulatedSuccess, "Simulation checked");
equal(arguments.length, 4, "Argument checked");
ok(this === dsTestDriver.ds, "Context checked");
equal(errorText, dsTestDriver.errorValue, "errorText checked");
start();
},
onCommitValidationError: function (httpStatus, errorText, jqXHR, submitResult) {
ok(true, "Callback called");
ok(!dsTestDriver.simulatedSuccess, "Simulation checked");
equal(arguments.length, 4, "Argument checked");
ok(this === dsTestDriver.ds, "Context checked");
equal(errorText, dsTestDriver.validationError.SubmitChangesResult[0].ValidationErrors[0].Message, "Validation text checked");
start();
}
};
})(this, upshot);

View File

@@ -0,0 +1,349 @@
/// <reference path="../Scripts/References.js" />
(function (global, upshot, undefined) {
module("DataSource.tests.js", {
teardown: function () {
testHelper.unmockAjax();
}
});
function createRemoteDataSource(options) {
options = $.extend({ providerParameters: { url: "unused", operationName: "" }, provider: upshot.riaDataProvider }, options || {});
return new upshot.RemoteDataSource(options);
}
function createTestDataContext() {
return new upshot.DataContext(new upshot.riaDataProvider());
}
// refreshStart
test("refreshStart RemoteDataSource", 3, function () {
stop();
dsTestDriver.simulateSuccessService();
dsTestDriver.ds = upshot.RemoteDataSource({ providerParameters: { url: "unused", operationName: "" }, provider: upshot.riaDataProvider });
dsTestDriver.ds.bind("refreshStart", dsTestDriver.onRefreshStart);
dsTestDriver.ds.refresh(function () { start(); });
});
test("refreshStart observer LocalDataSource over RemoteDataSource", 3, function () {
stop();
dsTestDriver.simulateSuccessService();
dsTestDriver.ds = upshot.LocalDataSource({ source: createRemoteDataSource() });
dsTestDriver.ds.bind({
refreshStart: dsTestDriver.onRefreshStart,
refreshSuccess: function () { start(); }
});
dsTestDriver.ds.refresh({ all: true });
});
test("refreshStart observer LocalDataSource over EntitySet", 3, function () {
stop();
dsTestDriver.simulateSuccessService();
var dataContext = upshot.DataContext(new upshot.riaDataProvider());
dataContext.__load({ providerParameters: { url: "unused", operationName: ""} }, function (entitySet) {
dsTestDriver.ds = new upshot.LocalDataSource({ source: entitySet });
dsTestDriver.ds.bind("refreshStart", dsTestDriver.onRefreshStart);
dsTestDriver.ds.bind("refreshSuccess", function () { start(); });
dsTestDriver.ds.refresh();
});
});
// refreshSuccess
test("refreshSuccess RemoteDataSource", 6, function () {
stop();
dsTestDriver.simulateSuccessService();
dsTestDriver.ds = createRemoteDataSource();
dsTestDriver.ds.refresh(dsTestDriver.onRefreshSuccess, dsTestDriver.onRefreshError);
});
test("refreshSuccess observer RemoteDataSource", 6, function () {
stop();
dsTestDriver.simulateSuccessService();
dsTestDriver.ds = createRemoteDataSource();
dsTestDriver.ds.bind("refreshSuccess", dsTestDriver.onRefreshSuccess);
dsTestDriver.ds.bind("refreshError", dsTestDriver.onRefreshError);
dsTestDriver.ds.refresh();
});
test("refreshSuccess LocalDataSource over RemoteDataSource", 6, function () {
stop();
dsTestDriver.simulateSuccessService();
dsTestDriver.ds = new upshot.LocalDataSource({ source: createRemoteDataSource() });
dsTestDriver.ds.refresh({ all: true }, dsTestDriver.onRefreshSuccess, dsTestDriver.onRefreshError);
});
test("refreshSuccess observer LocalDataSource over RemoteDataSource", 6, function () {
stop();
dsTestDriver.simulateSuccessService();
dsTestDriver.ds = new upshot.LocalDataSource({ source: createRemoteDataSource() })
.bind("refreshSuccess", dsTestDriver.onRefreshSuccess)
.bind("refreshError", dsTestDriver.onRefreshError);
dsTestDriver.ds.refresh({ all: true });
});
test("refreshSuccess LocalDataSource over EntitySet", 6, function () {
stop();
dsTestDriver.simulateSuccessService();
var dataContext = createTestDataContext();
dataContext.__load({ providerParameters: { url: "unused"} }, function (entitySet) {
dsTestDriver.ds = new upshot.LocalDataSource({ source: entitySet });
dsTestDriver.ds.refresh(dsTestDriver.onRefreshSuccess, dsTestDriver.onRefreshError);
});
});
test("refreshSuccess observer LocalDataSource over EntitySet", 6, function () {
stop();
dsTestDriver.simulateSuccessService();
var dataContext = createTestDataContext();
dataContext.__load({ providerParameters: { url: "unused"} }, function (entitySet) {
dsTestDriver.ds = new upshot.LocalDataSource({ source: entitySet })
.bind({
refreshSuccess: dsTestDriver.onRefreshSuccess,
refreshError: dsTestDriver.onRefreshError
});
dsTestDriver.ds.refresh();
});
});
// refreshError
test("refreshError RemoteDataSource", 5, function () {
stop();
dsTestDriver.simulateErrorService();
dsTestDriver.ds = createRemoteDataSource();
dsTestDriver.ds.refresh(dsTestDriver.onRefreshSuccess, dsTestDriver.onRefreshError);
});
test("refreshError observer RemoteDataSource", 5, function () {
stop();
dsTestDriver.simulateErrorService();
dsTestDriver.ds = createRemoteDataSource();
dsTestDriver.ds.bind("refreshSuccess", dsTestDriver.onRefreshSuccess);
dsTestDriver.ds.bind("refreshError", dsTestDriver.onRefreshError);
dsTestDriver.ds.refresh();
});
test("refreshError LocalDataSource over RemoteDataSource", 5, function () {
stop();
dsTestDriver.simulateErrorService();
dsTestDriver.ds = new upshot.LocalDataSource({ source: createRemoteDataSource() });
dsTestDriver.ds.refresh({ all: true }, dsTestDriver.onRefreshSuccess, dsTestDriver.onRefreshError);
});
test("refreshError observer LocalDataSource over RemoteDataSource", 5, function () {
stop();
dsTestDriver.simulateErrorService();
dsTestDriver.ds = new upshot.LocalDataSource({ source: createRemoteDataSource() });
dsTestDriver.ds.bind("refreshSuccess", dsTestDriver.onRefreshSuccess);
dsTestDriver.ds.bind("refreshError", dsTestDriver.onRefreshError);
dsTestDriver.ds.refresh({ all: true });
});
// entityChanged
asyncTest("entityChanged event is raised on a successful update", 12, function () {
var listener = {
events: [],
onEntityUpdated: function (entity, path, eventArgs) {
listener.events.push({ entity: entity, path: path, eventArgs: eventArgs });
}
};
dsTestDriver.ds = new upshot.RemoteDataSource({ providerParameters: { url: "unused", operationName: "" }, provider: upshot.riaDataProvider, entityType: "Product:#Sample.Models", bufferChanges: true });
dsTestDriver.ds.bind("entityUpdated", listener.onEntityUpdated);
dsTestDriver.simulateSuccessService();
dsTestDriver.ds.refresh(function (entities) {
var entity = entities[0];
equal(dsTestDriver.ds.isUpdated(entity), false, "The entity should not have changes");
equal(listener.events.length, 0, "There should have been one event");
$.observable(entity).property("Price", 700);
equal(dsTestDriver.ds.isUpdated(entity), true, "The entity should have changes");
equal(listener.events.length, 1, "There should have been one event");
equal(listener.events[0].entity, entity, "The event should have been for the entity");
equal(listener.events[0].path, "", "The event should have been directly on the entity");
equal(listener.events[0].eventArgs.newValues.Price, 700, "The event should have been a property change");
listener.events.length = 0;
dsTestDriver.simulatePostSuccessService();
dsTestDriver.ds.commitChanges(function () {
equal(dsTestDriver.ds.isUpdated(entity), false, "The entity should no longer have changes");
equal(listener.events.length, 1, "There should have been one event");
equal(listener.events[0].entity, entity, "The event should have been for the entity");
equal(listener.events[0].path, undefined, "The event should not include a path");
equal(listener.events[0].eventArgs, undefined, "The event should not include args");
start();
});
});
});
test("insert without initial refresh over RemoteDataSource", 5, function () {
stop();
dsTestDriver.ds = new upshot.RemoteDataSource({
providerParameters: { url: "unused" },
provider: upshot.riaDataProvider,
entityType: "Foo"
});
dsTestDriver.ds.bind("commitSuccess", dsTestDriver.onCommitSuccess);
upshot.metadata("Foo", { key: ["FooId"] });
dsTestDriver.simulatePostSuccessService();
$.observable(dsTestDriver.ds.getEntities()).insert({ FooId: 1 });
});
test("revertChanges without initial refresh over RemoteDataSource", 2, function () {
stop();
var entities = [],
ds = new upshot.RemoteDataSource({
entityType: "Foo",
result: entities,
bufferChanges: true,
provider: upshot.riaDataProvider
});
upshot.metadata("Foo", { key: ["FooId"] });
$.observable(entities).insert({});
equal(entities.length, 1);
ds.revertChanges();
equal(entities.length, 0);
start();
});
test("DataSource reset", 23, function () {
stop();
dsTestDriver.simulateSuccessService();
var rds = dsTestDriver.ds = createRemoteDataSource();
rds.refresh(function () {
stop();
dsTestDriver.onRefreshSuccess.apply(this, arguments);
var lds = upshot.LocalDataSource({ source: rds });
lds.refresh(function () {
// RDS and LDS should be loaded and in sync.
equal(lds.refreshNeeded(), false, "LocalDataSource should not need refresh");
ok(upshot.sameArrayContents(rds.getEntities(), lds.getEntities()), "LocalDataSource refreshed properly");
rds.reset();
// RDS should have been reset. LDS should need a refresh.
equal(rds.getEntities().length, 0, "RemoteDataSource has no entities");
equal(rds.getTotalEntityCount(), undefined, "RemoteDataSource has no total count");
equal(lds.refreshNeeded(), true, "LocalDataSource should need a refresh");
lds.reset();
// LDS should have been reset.
equal(lds.getEntities().length, 0, "LocalDataSource has no entities");
equal(lds.getTotalEntityCount(), undefined, "LocalDataSource has no total count");
// Put the RDS back in its loaded state.
dsTestDriver.simulateSuccessService();
rds.refresh(function () {
stop();
dsTestDriver.onRefreshSuccess.apply(this, arguments);
// Put the LDS back in sync with the RDS.
equal(lds.refreshNeeded(), true, "LocalDataSource should need a refresh");
lds.refresh(function () {
ok(upshot.sameArrayContents(rds.getEntities(), lds.getEntities()), "LocalDataSource refreshed properly");
lds.reset();
// LDS should have been reset.
equal(lds.getEntities().length, 0, "LocalDataSource has no entities");
equal(lds.getTotalEntityCount(), undefined, "LocalDataSource has no total count");
start();
});
});
});
});
});
test("refresh with edits", 5, function () {
stop();
var rds = dsTestDriver.ds = createRemoteDataSource();
dsTestDriver.simulateSuccessService();
rds.refresh(function (entities) {
ok(entities.length === 3, "Successful initial refresh");
var entity = entities[0];
$.observable(entity).property("Manufacturer", "Foo");
var exception;
try {
rds.refresh();
} catch (ex) {
exception = true;
}
ok(!!exception, "Can't load with edits to DataSource entities");
rds.revertChanges();
setTimeout(function () {
var emptyProductsResult = {
GetProductsResult: {
TotalCount: 3,
RootResults: [],
Metadata: [ $.extend({}, { type: "Product:#Sample.Models" }, upshot.metadata()["Product:#Sample.Models"]) ]
}
};
dsTestDriver.simulateSuccessService(emptyProductsResult);
rds.refresh(function (entities) {
ok(entities.length === 0, "'Canon' isn't in filtered result");
$.observable(entity).property("Manufacturer", "Foo");
setTimeout(function () {
var exception;
try {
dsTestDriver.simulateSuccessService(emptyProductsResult);
rds.refresh(function(entities) {
ok(entities.length === 0, "Can load with edits not included in DataSource entities");
start();
});
} catch (ex) {
exception = true;
}
ok(!exception, "Can load with edits not included in DataSource entities");
}, 0);
});
}, 0);
});
});
test("refresh with edits and 'allowRefreshWithEdits' option", 3, function () {
stop();
var rds = dsTestDriver.ds = createRemoteDataSource({ allowRefreshWithEdits: true });
dsTestDriver.simulateSuccessService();
rds.refresh(function (entities) {
ok(entities.length === 3, "Successful initial refresh");
var entity = entities[0];
$.observable(entity).property("Manufacturer", "Foo");
setTimeout(function () {
var exception;
try {
dsTestDriver.simulateSuccessService();
rds.refresh(function (entities) {
ok(entities.length === 3, "Can load with edits to DataSource entities (using allowRefreshWithEdits)");
start();
});
} catch (ex) {
exception = true;
}
ok(!exception, "Can load with edits to DataSource entities (using allowRefreshWithEdits)");
}, 0);
});
});
})(this, upshot);

View File

@@ -0,0 +1,257 @@
/// <reference path="../Scripts/References.js" />
(function (global, upshot, undefined) {
var datasets = {
primitives: {
create: function (id) {
return {
Id: id || 0,
B: true,
N: 1,
S: "A"
};
},
count: 4
},
scalars: {
create: function (id) {
return {
Id: id || 0,
B: true,
N: 1,
S: "A",
D: new Date(2011, 0, 1),
_: null
};
},
count: 6
},
nested: {
create: function (id) {
return {
Id: id || 0,
B: true,
N: 1,
S: "A",
O: {
B: true,
N: 1,
S: "A"
}
};
},
count: 8
},
tree: {
create: function (id) {
return {
Id: id || 0,
B: true,
N: 1,
S: "A",
O: {
B: true,
N: 1,
S: "A",
O1: {
B: true,
N: 1,
S: "A"
},
O2: {
B: true,
N: 1,
S: "A"
}
}
};
},
count: 16
},
array: {
create: function (id) {
return {
Id: id || 0,
B: true,
N: 1,
S: "A",
A: [{
B: true,
N: 1,
S: "A"
},
{
B: true,
N: 1,
S: "A"
}
]
};
},
count: 13
},
nestedArrays: {
create: function (id) {
return {
Id: id || 0,
B: true,
N: 1,
S: "A",
A: [{
B: true,
N: 1,
S: "A",
A: [{
B: true,
N: 1,
S: "A"
}
]
},
{
B: true,
N: 1,
S: "A",
A: [{
B: true,
N: 1,
S: "A"
}
]
}
]
};
},
count: 23
},
ko_primitives: function (id, extend) {
var obj = {
Id: ko.observable(id || 0),
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A")
};
if (extend) {
upshot.addEntityProperties(obj);
upshot.addUpdatedProperties(obj);
}
return obj;
},
ko_tree: function (id, extend) {
var obj = {
Id: ko.observable(id || 0),
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A"),
O: ko.observable({
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A"),
O1: ko.observable({
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A")
}),
O2: ko.observable({
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A")
})
})
};
if (extend) {
upshot.addEntityProperties(obj);
upshot.addUpdatedProperties(obj);
upshot.addUpdatedProperties(obj.O());
upshot.addUpdatedProperties(obj.O().O1());
upshot.addUpdatedProperties(obj.O().O2());
}
return obj;
},
ko_array: function (id, extend) {
var obj = {
Id: ko.observable(id || 0),
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A"),
A: ko.observableArray([
{
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A")
},
{
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A")
}
])
};
if (extend) {
upshot.addEntityProperties(obj);
upshot.addUpdatedProperties(obj);
upshot.addUpdatedProperties(obj.A()[0]);
upshot.addUpdatedProperties(obj.A()[1]);
}
return obj;
},
ko_nestedArrays: function (id, extend) {
var obj = {
Id: ko.observable(id || 0),
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A"),
A: ko.observableArray([
{
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A"),
A: ko.observableArray([
{
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A")
}
])
},
{
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A"),
A: ko.observableArray([
{
B: ko.observable(true),
N: ko.observable(1),
S: ko.observable("A")
}
])
}
])
};
if (extend) {
upshot.addEntityProperties(obj);
upshot.addUpdatedProperties(obj);
upshot.addUpdatedProperties(obj.A()[0]);
upshot.addUpdatedProperties(obj.A()[0].A()[0]);
upshot.addUpdatedProperties(obj.A()[1]);
upshot.addUpdatedProperties(obj.A()[1].A()[0]);
}
return obj;
}
};
upshot.test || (upshot.test = {});
upshot.test.datasets = datasets;
})(this, upshot);

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More