You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ko...@apache.org on 2014/04/07 15:37:06 UTC
[02/11] [OLINGO-238] Build infrastructure for datajs I
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/e29bbd8f/datajs/tests/odata-atom-tests.js
----------------------------------------------------------------------
diff --git a/datajs/tests/odata-atom-tests.js b/datajs/tests/odata-atom-tests.js
new file mode 100644
index 0000000..52c0c94
--- /dev/null
+++ b/datajs/tests/odata-atom-tests.js
@@ -0,0 +1,4756 @@
+/// <reference path="../src/odata-utils.js" />
+/// <reference path="../src/odata-handler.js" />
+/// <reference path="../src/odata-atom.js" />
+/// <reference path="../src/odata-xml.js" />
+/// <reference path="common/djstest.js" />
+
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// 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.
+
+// odata-atom-tests.js
+
+(function (window, undefined) {
+
+ module("Unit");
+
+ var parseMetadataHelper = function (text) {
+ var response = { statusCode: 200, body: text, headers: { "Content-Type": "application/xml"} };
+ OData.metadataHandler.read(response, {});
+ return response.data;
+ };
+
+ var resetFoodData = function () {
+ $.ajax({ url: "./endpoints/FoodStoreDataServiceV2.svc/ResetData", async: false, type: "POST" });
+ };
+
+ var customerSampleMetadataText = '' +
+ '<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">\r\n' +
+ '<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="2.0">\r\n' +
+ '<Schema Namespace="Ns" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns="http://schemas.microsoft.com/ado/2006/04/edm">\r\n' +
+ ' <EntityType Name="Customer">\r\n' +
+ ' <Key><PropertyRef Name="ID" /></Key>\r\n' +
+ ' <Property Name="ID" Type="Edm.Int32" Nullable="false" />\r\n' +
+ ' <Property Name="Name" Type="Edm.String" Nullable="true" m:FC_TargetPath="SyndicationSummary" m:FC_ContentKind="xhtml" m:FC_KeepInContent="false" />\r\n' +
+ ' <Property Name="LastName" Type="Edm.String" Nullable="true" m:FC_TargetPath="foo/bar/@baz" m:FC_NsUri="htp://prefix" m:FC_NsPrefix="prefix" m:FC_KeepInContent="false" />\r\n' +
+ ' <Property Name="FavoriteNumber" Type="Edm.Int32" Nullable="true" m:FC_TargetPath="favorite/number" m:FC_NsUri="htp://prefix" m:FC_NsPrefix="prefix" m:FC_KeepInContent="false" />\r\n' +
+ ' <Property Name="Address" Type="Ns.Address" Nullable="false" \r\n' +
+ ' m:FC_TargetPath="foo/bar/@city" m:FC_NsUri="htp://prefix" m:FC_NsPrefix="prefix" m:FC_SourcePath="City" m:FC_KeepInContent="false" \r\n' +
+ ' m:FC_TargetPath_1="foo/bar" m:FC_NsUri_1="htp://prefix" m:FC_NsPrefix_1="prefix" m:FC_SourcePath_1="Street" m:FC_KeepInContent_1="false" />\r\n' +
+ ' </EntityType>\r\n' +
+ ' <ComplexType Name="Address">\r\n' +
+ ' <Property Name="Street" Type="Edm.String" Nullable="true" />\r\n' +
+ ' <Property Name="City" Type="Edm.String" Nullable="true" />\r\n' +
+ ' </ComplexType>\r\n' +
+ ' <EntityContainer Name="SampleContext" m:IsDefaultEntityContainer="true">\r\n' +
+ ' <EntitySet Name="Customers" EntityType="Ns.Customer" />\r\n' +
+ ' </EntityContainer>\r\n' +
+ '</Schema>\r\n' +
+ '</edmx:DataServices></edmx:Edmx>';
+
+ var foodServiceV2FoodsSampleText = '' +
+ '<feed xml:base="http://localhost/tests/endpoints/FoodStoreDataServiceV2.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">' +
+ ' <title type="text">Foods</title>' +
+ ' <id>http://localhost/tests/endpoints/FoodStoreDataServiceV2.svc/Foods</id>' +
+ ' <updated>2010-12-28T23:09:54Z</updated>' +
+ ' <link rel="self" title="Foods" href="Foods" />' +
+ ' <entry>' +
+ ' <id>http://localhost/tests/endpoints/FoodStoreDataServiceV2.svc/Foods(0)</id>' +
+ ' <title type="text">flour</title>' +
+ ' <updated>2010-12-28T23:09:54Z</updated>' +
+ ' <author><name /></author>' +
+ ' <link rel="edit" title="Food" href="Foods(0)" />' +
+ ' <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Category" type="application/atom+xml;type=entry" title="Category" href="Foods(0)/Category" />' +
+ ' <category term="DataJS.Tests.V2.Food" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />' +
+ ' <content type="application/xml">' +
+ ' <m:properties>' +
+ ' <d:FoodID m:type="Edm.Int32">0</d:FoodID>' +
+ ' <d:Name>flour</d:Name>' +
+ ' <d:ServingSize m:type="Edm.Decimal">1</d:ServingSize>' +
+ ' <d:MeasurementUnit>Cup</d:MeasurementUnit>' +
+ ' <d:ProteinGrams m:type="Edm.Byte">3</d:ProteinGrams>' +
+ ' <d:FatGrams m:type="Edm.Int16">1</d:FatGrams>' +
+ ' <d:CarbohydrateGrams m:type="Edm.Int32">20</d:CarbohydrateGrams>' +
+ ' <d:CaloriesPerServing m:type="Edm.Int64">140</d:CaloriesPerServing>' +
+ ' <d:IsAvailable m:type="Edm.Boolean">true</d:IsAvailable>' +
+ ' <d:ExpirationDate m:type="Edm.DateTime">2010-12-25T12:00:00</d:ExpirationDate>' +
+ ' <d:ItemGUID m:type="Edm.Guid">27272727-2727-2727-2727-272727272727</d:ItemGUID>' +
+ ' <d:Weight m:type="Edm.Single">10</d:Weight>' +
+ ' <d:AvailableUnits m:type="Edm.SByte">1</d:AvailableUnits>' +
+ ' <d:Packaging m:type="DataJS.Tests.V2.Package">' +
+ ' <d:Type m:null="true" />' +
+ ' <d:Color></d:Color>' +
+ ' <d:NumberPerPackage m:type="Edm.Int32">2147483647</d:NumberPerPackage>' +
+ ' <d:RequiresRefridgeration m:type="Edm.Boolean">false</d:RequiresRefridgeration>' +
+ ' <d:ShipDate m:type="Edm.DateTime">0001-01-01T00:00:00</d:ShipDate>' +
+ ' <d:PackageDimensions m:type="DataJS.Tests.V2.Dimensions">' +
+ ' <d:Length m:type="Edm.Decimal">79228162514264337593543950335</d:Length>' +
+ ' <d:Height m:type="Edm.Int16">32767</d:Height>' +
+ ' <d:Width m:type="Edm.Int64">9223372036854775807</d:Width>' +
+ ' <d:Volume m:type="Edm.Double">1.7976931348623157E+308</d:Volume>' +
+ ' </d:PackageDimensions>' +
+ ' </d:Packaging>' +
+ ' </m:properties>' +
+ ' </content>' +
+ ' <cooked:cooked cooked:length="2" cooked:height="1" cooked:width="3" xmlns:cooked="http://www.example.org/cooked/">' +
+ ' <cooked:volume>6</cooked:volume>' +
+ ' </cooked:cooked>' +
+ ' <pr:price pr:value="0.19999" xmlns:pr="http://www.example.org/price/"></pr:price>' +
+ ' </entry>' +
+ ' <entry>' +
+ ' <id>http://localhost/tests/endpoints/FoodStoreDataServiceV2.svc/Foods(1)</id>' +
+ ' <title type="text">sugar</title>' +
+ ' <updated>2010-12-28T23:09:54Z</updated>' +
+ ' <author>' +
+ ' <name />' +
+ ' </author>' +
+ ' <link rel="edit" title="Food" href="Foods(1)" />' +
+ ' <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Category" type="application/atom+xml;type=entry" title="Category" href="Foods(1)/Category" />' +
+ ' <category term="DataJS.Tests.V2.Food" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />' +
+ ' <content type="application/xml">' +
+ ' <m:properties>' +
+ ' <d:FoodID m:type="Edm.Int32">1</d:FoodID>' +
+ ' <d:Name>sugar</d:Name>' +
+ ' <d:ServingSize m:type="Edm.Decimal">1</d:ServingSize>' +
+ ' <d:MeasurementUnit>tsp</d:MeasurementUnit>' +
+ ' <d:ProteinGrams m:type="Edm.Byte">0</d:ProteinGrams>' +
+ ' <d:FatGrams m:type="Edm.Int16">0</d:FatGrams>' +
+ ' <d:CarbohydrateGrams m:type="Edm.Int32">4</d:CarbohydrateGrams>' +
+ ' <d:CaloriesPerServing m:type="Edm.Int64">16</d:CaloriesPerServing>' +
+ ' <d:IsAvailable m:type="Edm.Boolean">false</d:IsAvailable>' +
+ ' <d:ExpirationDate m:type="Edm.DateTime">2011-12-28T00:00:00</d:ExpirationDate>' +
+ ' <d:ItemGUID m:type="Edm.Guid">ffffffff-ffff-ffff-ffff-ffffffffffff</d:ItemGUID>' +
+ ' <d:Weight m:type="Edm.Single">0.1</d:Weight>' +
+ ' <d:AvailableUnits m:type="Edm.SByte">0</d:AvailableUnits>' +
+ ' <d:Packaging m:type="DataJS.Tests.V2.Package">' +
+ ' <d:Type xml:space="preserve"> </d:Type>' +
+ ' <d:Color>BLUE</d:Color>' +
+ ' <d:NumberPerPackage m:type="Edm.Int32">-2147483648</d:NumberPerPackage>' +
+ ' <d:RequiresRefridgeration m:type="Edm.Boolean">true</d:RequiresRefridgeration>' +
+ ' <d:ShipDate m:type="Edm.DateTime">0001-01-01T00:00:00</d:ShipDate>' +
+ ' <d:PackageDimensions m:type="DataJS.Tests.V2.Dimensions">' +
+ ' <d:Length m:type="Edm.Decimal">-79228162514264337593543950335</d:Length>' +
+ ' <d:Height m:type="Edm.Int16">-32768</d:Height>' +
+ ' <d:Width m:type="Edm.Int64">-9223372036854775808</d:Width>' +
+ ' <d:Volume m:type="Edm.Double">-1.7976931348623157E+308</d:Volume>' +
+ ' </d:PackageDimensions>' +
+ ' </d:Packaging>' +
+ ' <d:CookedSize m:type="DataJS.Tests.V2.CookedDimensions" m:null="true" />' +
+ ' </m:properties>' +
+ ' </content>' +
+ ' <cooked:cooked cooked:length="" cooked:height="" cooked:width="" xmlns:cooked="http://www.example.org/cooked/">' +
+ ' <cooked:volume></cooked:volume>' +
+ ' </cooked:cooked>' +
+ ' <pr:price pr:value="0.2" xmlns:pr="http://www.example.org/price/"></pr:price>' +
+ ' </entry>' +
+ '</feed>';
+
+ var foodServiceV2MetadataText = '' +
+ '<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">' +
+ ' <edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="2.0">' +
+ ' <Schema Namespace="DataJS.Tests.V2" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns="http://schemas.microsoft.com/ado/2007/05/edm">' +
+ ' <EntityType Name="Category">' +
+ ' <Key>' +
+ ' <PropertyRef Name="CategoryID" />' +
+ ' </Key>' +
+ ' <Property Name="CategoryID" Type="Edm.Int32" Nullable="false" />' +
+ ' <Property Name="Name" Type="Edm.String" Nullable="true" m:FC_TargetPath="SyndicationTitle" m:FC_ContentKind="text" m:FC_KeepInContent="true" />' +
+ ' <NavigationProperty Name="Foods" Relationship="DataJS.Tests.V2.Category_Foods" FromRole="Category" ToRole="Foods" />' +
+ ' </EntityType>' +
+ ' <EntityType Name="PreparedFood" BaseType="DataJS.Tests.V2.Food">' +
+ ' <Property Name="Instructions" Type="Edm.String" Nullable="true" />' +
+ ' <Property Name="NumberOfIngredients" Type="Edm.Single" Nullable="false" />' +
+ ' </EntityType>' +
+ ' <EntityType Name="Food">' +
+ ' <Key>' +
+ ' <PropertyRef Name="FoodID" />' +
+ ' </Key>' +
+ ' <Property Name="FoodID" Type="Edm.Int32" Nullable="false" />' +
+ ' <Property Name="Name" Type="Edm.String" Nullable="true" m:FC_TargetPath="SyndicationTitle" m:FC_ContentKind="text" m:FC_KeepInContent="true" />' +
+ ' <Property Name="UnitPrice" Type="Edm.Double" Nullable="false" m:FC_TargetPath="price/@value" m:FC_NsUri="http://www.example.org/price/" m:FC_NsPrefix="pr" m:FC_KeepInContent="false" />' +
+ ' <Property Name="ServingSize" Type="Edm.Decimal" Nullable="false" />' +
+ ' <Property Name="MeasurementUnit" Type="Edm.String" Nullable="true" />' +
+ ' <Property Name="ProteinGrams" Type="Edm.Byte" Nullable="false" />' +
+ ' <Property Name="FatGrams" Type="Edm.Int16" Nullable="false" />' +
+ ' <Property Name="CarbohydrateGrams" Type="Edm.Int32" Nullable="false" />' +
+ ' <Property Name="CaloriesPerServing" Type="Edm.Int64" Nullable="false" />' +
+ ' <Property Name="IsAvailable" Type="Edm.Boolean" Nullable="false" />' +
+ ' <Property Name="ExpirationDate" Type="Edm.DateTime" Nullable="false" />' +
+ ' <Property Name="ItemGUID" Type="Edm.Guid" Nullable="false" />' +
+ ' <Property Name="Weight" Type="Edm.Single" Nullable="false" />' +
+ ' <Property Name="AvailableUnits" Type="Edm.SByte" Nullable="false" />' +
+ ' <Property Name="Packaging" Type="DataJS.Tests.V2.Package" Nullable="false" />' +
+ ' <Property Name="CookedSize" Type="DataJS.Tests.V2.CookedDimensions" Nullable="false" m:FC_TargetPath="cooked/volume" m:FC_NsUri="http://www.example.org/cooked/" m:FC_NsPrefix="cooked" m:FC_SourcePath="Volume" m:FC_KeepInContent="false" m:FC_TargetPath_1="cooked/@width" m:FC_NsUri_1="http://www.example.org/cooked/" m:FC_NsPrefix_1="cooked" m:FC_SourcePath_1="Width" m:FC_KeepInContent_1="false" m:FC_TargetPath_2="cooked/@height" m:FC_NsUri_2="http://www.example.org/cooked/" m:FC_NsPrefix_2="cooked" m:FC_SourcePath_2="Height" m:FC_KeepInContent_2="false" m:FC_TargetPath_3="cooked/@length" m:FC_NsUri_3="http://www.example.org/cooked/" m:FC_NsPrefix_3="cooked" m:FC_SourcePath_3="Length" m:FC_KeepInContent_3="false" />' +
+ ' <NavigationProperty Name="Category" Relationship="DataJS.Tests.V2.Food_Category" FromRole="Food" ToRole="Category" />' +
+ ' </EntityType>' +
+ ' <ComplexType Name="Package">' +
+ ' <Property Name="Type" Type="Edm.String" Nullable="true" />' +
+ ' <Property Name="Color" Type="Edm.String" Nullable="true" />' +
+ ' <Property Name="NumberPerPackage" Type="Edm.Int32" Nullable="false" />' +
+ ' <Property Name="RequiresRefridgeration" Type="Edm.Boolean" Nullable="false" />' +
+ ' <Property Name="ShipDate" Type="Edm.DateTime" Nullable="false" />' +
+ ' <Property Name="PackageDimensions" Type="DataJS.Tests.V2.Dimensions" Nullable="false" />' +
+ ' </ComplexType>' +
+ ' <ComplexType Name="Dimensions">' +
+ ' <Property Name="Length" Type="Edm.Decimal" Nullable="false" />' +
+ ' <Property Name="Height" Type="Edm.Int16" Nullable="false" />' +
+ ' <Property Name="Width" Type="Edm.Int64" Nullable="false" />' +
+ ' <Property Name="Volume" Type="Edm.Double" Nullable="false" />' +
+ ' </ComplexType>' +
+ ' <ComplexType Name="CookedDimensions">' +
+ ' <Property Name="Length" Type="Edm.Decimal" Nullable="false" />' +
+ ' <Property Name="Height" Type="Edm.Int16" Nullable="false" />' +
+ ' <Property Name="Width" Type="Edm.Int64" Nullable="false" />' +
+ ' <Property Name="Volume" Type="Edm.Double" Nullable="false" />' +
+ ' </ComplexType>' +
+ ' <Association Name="Category_Foods">' +
+ ' <End Role="Category" Type="DataJS.Tests.V2.Category" Multiplicity="*" />' +
+ ' <End Role="Foods" Type="DataJS.Tests.V2.Food" Multiplicity="*" />' +
+ ' </Association>' +
+ ' <Association Name="Food_Category">' +
+ ' <End Role="Food" Type="DataJS.Tests.V2.Food" Multiplicity="*" />' +
+ ' <End Role="Category" Type="DataJS.Tests.V2.Category" Multiplicity="0..1" />' +
+ ' </Association>' +
+ ' <EntityContainer Name="FoodContainer" m:IsDefaultEntityContainer="true">' +
+ ' <EntitySet Name="Categories" EntityType="DataJS.Tests.V2.Category" />' +
+ ' <EntitySet Name="Foods" EntityType="DataJS.Tests.V2.Food" />' +
+ ' <AssociationSet Name="Category_Foods" Association="DataJS.Tests.Category_Foods">' +
+ ' <End Role="Category" EntitySet="Categories" />' +
+ ' <End Role="Foods" EntitySet="Foods" />' +
+ ' </AssociationSet>' +
+ ' <AssociationSet Name="Food_Category" Association="DataJS.Tests.V2.Food_Category">' +
+ ' <End Role="Food" EntitySet="Foods" />' +
+ ' <End Role="Category" EntitySet="Categories" />' +
+ ' </AssociationSet>' +
+ ' <FunctionImport Name="ResetData" m:HttpMethod="POST" />' +
+ ' <FunctionImport Name="FoodsAvailable" ReturnType="Collection(Edm.String)" m:HttpMethod="GET" />' +
+ ' <FunctionImport Name="PackagingTypes" ReturnType="Collection(DataJS.Tests.V2.Package)" m:HttpMethod="GET" />' +
+ ' </EntityContainer>' +
+ ' </Schema>' +
+ ' </edmx:DataServices>' +
+ '</edmx:Edmx>';
+
+ djstest.addTest(function applyEntryCustomizationToEntryTest() {
+ var metadata = parseMetadataHelper(customerSampleMetadataText);
+ var data = { __metadata: { type: "Ns.Customer" }, Name: "Name", LastName: "Last Name", Address: { Street: "Street Value", City: "City Value" }, FavoriteNumber: 123 };
+ var request = { data: data, headers: { "Content-Type": "application/atom+xml"} };
+ OData.atomHandler.write(request, { metadata: metadata });
+
+ djstest.assert(request.body !== null, "request.body !== null");
+ djstest.assert(request.body.indexOf("<a:summary type=\"xhtml\">Name</a:summary>") !== -1, 'request.body.indexOf("<a:summary>Name</a:summary>") !== -1');
+ djstest.assert(request.body.indexOf('baz="Last Name"') !== -1, 'request.body.indexOf(baz="Last Name") !== -1');
+ djstest.assert(request.body.indexOf('city="City Value"') !== -1, 'request.body.indexOf(city="City Value") !== -1');
+ djstest.assert(request.body.indexOf('<prefix:foo ') !== -1, "request.body.indexOf('<prefix:foo ') !== -1");
+ djstest.assert(request.body.indexOf('term="Ns.Customer"') !== -1, "request.body.indexOf(term='Ns.Customer') !== -1");
+ djstest.assert(request.body.indexOf('>123</') !== -1, "request.body.indexOf(>123</) !== -1");
+
+ // Try with other mapping types.
+ metadata.dataServices.schema[0].entityType[0].property[1].FC_ContentKind = "html";
+ request.body = undefined;
+ OData.atomHandler.write(request, { metadata: metadata });
+ djstest.assert(request.body.indexOf("<a:summary type=\"html\">Name</a:summary>") !== -1, 'request.body.indexOf("<a:summary type="html">Name</a:summary>") !== -1');
+
+ // Try with a null value now.
+ request.data.FavoriteNumber = null;
+ request.body = null;
+ OData.atomHandler.write(request, { metadata: metadata });
+ djstest.assert(request.body.indexOf('>123</') === -1, "request.body.indexOf(>123</) === -1");
+ djstest.assert(request.body.indexOf('m:null="true"') !== -1, "request.body.indexOf(m:null=true) !== -1");
+
+ // Try with a null complex type now.
+ request.data.FavoriteNumber = 123;
+ request.data.Address = null;
+ request.body = null;
+ OData.atomHandler.write(request, { metadata: metadata });
+ djstest.assert(request.body.indexOf('Street') === -1, "request.body.indexOf(Street) === -1");
+ djstest.assert(request.body.indexOf('m:null="true"') !== -1, "request.body.indexOf(m:null=true) !== -1");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function normalizeHeadersReadTest() {
+ // Verifies that headers are normalized for reading.
+ // See issue at http://datajs.codeplex.com/workitem/148
+ window.MockHttpClient.clear().addResponse("/foo", {
+ statusCode: 200,
+ body: foodServiceV2FoodsSampleText,
+ headers: { "Accept": "application/json", "unknown": "u", "content-type": "application/atom+xml", "dataserviceversion": "2.0" }
+ });
+
+ OData.read("/foo", function (data, response) {
+ djstest.assertAreEqual(data.results.length, 2, "data.results.length has two entries");
+ djstest.assertAreEqual(response.headers.Accept, "application/json", "Accept available");
+ djstest.assertAreEqual(response.headers.unknown, "u", "u unmodified");
+ djstest.assertAreEqual(response.headers["Content-Type"], "application/atom+xml", "Content-Type available");
+ djstest.assertAreEqual(response.headers["DataServiceVersion"], "2.0", "DataServiceVersion available");
+ djstest.done();
+ }, undefined, undefined, MockHttpClient);
+ });
+
+ djstest.addTest(function normalizeHeadersWriteTest() {
+ // Verifies that headers are normalized for writing.
+ // See issue at http://datajs.codeplex.com/workitem/148
+ window.MockHttpClient.clear().addRequestVerifier("/foo", function (request) {
+ djstest.assertAreEqual(request.headers["Content-Type"], "application/atom+xml", "json found");
+ djstest.assert(request.body.indexOf(":bar") !== -1, "format recognized and applied as XML");
+ djstest.done();
+ });
+
+ var request = {
+ method: "POST",
+ requestUri: "/foo",
+ data: { "bar": 123 },
+ headers: { "content-type": "application/atom+xml" }
+ };
+ OData.request(request, function (data) {
+ }, undefined, undefined, MockHttpClient);
+ });
+
+ djstest.addTest(function testParsePrimitivePropertiesBasic() {
+ var feed = "\
+ <entry xml:base=\'http://services.odata.org/OData/OData.svc/\' \r\n\
+ xmlns:d=\'http://schemas.microsoft.com/ado/2007/08/dataservices\' \r\n\
+ xmlns:m=\'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\' \r\n\
+ xmlns:atom=\'http://www.w3.org/2005/Atom\' \r\n\
+ xmlns:app=\'http://www.w3.org/2007/app\' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\'>\r\n\
+ <id>http://services.odata.org/OData/OData.svc/the id</id> \r\n \
+ <content type='application/xml'>\r\n \
+ <m:properties xmlns=\'http://schemas.microsoft.com/ado/2007/08/dataservices\'>\r\n \
+ <Boolean m:type='Edm.Boolean'>true</Boolean>\r\n \
+ <Binary m:type='Edm.Binary'>01007A8A680D9E14A64EAC1242DD33C9DB05</Binary>\r\n \
+ <Byte m:type='Edm.Byte'>8</Byte>\r\n \
+ <DateTime m:type='Edm.DateTime'>2010-11-01T15:13:25</DateTime>\r\n \
+ <Decimal m:type='Edm.Decimal'>100.10</Decimal>\r\n \
+ <Guid m:type='Edm.Guid'>12345678-aaaa-bbbb-cccc-ddddeeeeffff</Guid>\r\n \
+ <!-- <Time m:type='Edm.Time'>P05DT12H30M05.125S</Time> --> \r\n \
+ <DateTimeOffset m:type='Edm.DateTimeOffset'>2010-11-01T15:13:25+10:00</DateTimeOffset>\r\n \
+ <Double m:type='Edm.Double'>1E+10</Double>\r\n \
+ <Single m:type='Edm.Single'>100.01</Single>\r\n \
+ <Int16 m:type='Edm.Int16'>16</Int16>\r\n \
+ <Int32 m:type='Edm.Int32'>32</Int32>\r\n \
+ <Int64 m:type='Edm.Int64'>64</Int64>\r\n \
+ <SByte m:type='Edm.SByte'>-8</SByte>\r\n \
+ </m:properties>\r\n \
+ </content>\r\n \
+ </entry>\r\n";
+
+ var response = { body: feed, headers: { "Content-Type": "application/atom+xml"} };
+ OData.atomHandler.read(response, {});
+
+ djstest.assertsExpected(1);
+ ODataReadOracle.readEntryLoopback(feed, function (expectedData) {
+ djstest.assertAreEqualDeep(response.data, expectedData, "Verify deserialized data");
+ djstest.done();
+ });
+ });
+
+ djstest.addTest(function deserializeCustomizationsNullAndXhtmlTest() {
+ var payload = "<entry " +
+ ' xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" \r\n' +
+ " xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' \r\n" +
+ " xmlns=\"http://www.w3.org/2005/Atom\">\r\n" +
+ " <id>http://localhost/tests/endpoints/FoodDataService.svc/Foods(1)</id> " +
+ " <author><name>Customer #1</name></author>" +
+ " <summary><b>Name</b></summary>" +
+ " <category term='Ns.Customer' scheme='http://schemas.microsoft.com/ado/2007/08/dataservices/scheme' /> " +
+ " <content type='application/xml'><m:properties><d:ID m:type='Edm.Int32'>1</d:ID>" +
+ " <d:LastName m:null='true' /></m:properties></content>" +
+ "</entry>";
+ var metadata = parseMetadataHelper(customerSampleMetadataText);
+ var response = { body: payload, headers: { "Content-Type": "application/atom+xml"} };
+ OData.atomHandler.read(response, { metadata: metadata });
+
+ djstest.assertAreEqual(response.data.LastName, null, "last name is null");
+ djstest.assertAreEqual(response.data.Name, "<b xmlns=\"http://www.w3.org/2005/Atom\">Name</b>", "name includes tags");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function parseCustomizationSampleTest() {
+ var payload = foodServiceV2FoodsSampleText;
+ var metadata = parseMetadataHelper(foodServiceV2MetadataText);
+ var response = { body: payload, headers: { "Content-Type": "application/atom+xml"} };
+ OData.atomHandler.read(response, { metadata: metadata });
+
+ djstest.assert(response.data !== null, "response.data !== null");
+ djstest.assert(response.data.results !== null, "response.data.results !== null");
+
+ var r = response.data.results;
+ djstest.assertAreEqual(r[0].__metadata.type, "DataJS.Tests.V2.Food", "r[0].__metadata.type");
+ djstest.assertAreEqual(r[0].Name, "flour", "r[0].Name");
+ djstest.assertAreEqual(r[0].UnitPrice, 0.19999, "r[0].UnitPrice");
+ djstest.assertAreEqual(r[0].ServingSize, 1, "r[0].ServingSize");
+
+ // CONSIDER: we intended to have complex type have their type annotation out-of-band, but JSON has it in-line; do we want to normalize this out everywhere?
+ // djstest.assertAreEqual(r[0].Packaging.__metadata.type, "DataJS.Tests.PackageV2", "r[0].Packaging.__metadata.type");
+ djstest.assertAreEqual(r[0].Packaging.Type, null, "package type for flour is null");
+ djstest.assertAreEqual(r[0].Packaging.PackageDimensions.Height, 32767, "r[0].Packaging.PackageDimensions.Height");
+
+ djstest.assertAreEqual(r[0].CookedSize.Length, 2, "r[0].CookedSize.Length");
+ djstest.assertAreEqual(r[0].CookedSize.Volume, 6, "r[0].CookedSize.Volume");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function parseIntoPropertiesTest() {
+ var payload = '' +
+ '<entry xml:base="http://localhost/tests/endpoints/FoodStoreDataServiceV2.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">' +
+ ' <id>http://localhost/tests/endpoints/FoodStoreDataServiceV2.svc/Foods(0)</id>' +
+ ' <title type="text">flour</title>' +
+ ' <updated>2010-12-28T23:09:54Z</updated>' +
+ ' <author><name /></author>' +
+ ' <link rel="edit" title="Food" href="Foods(0)" />' +
+ ' <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Category" type="application/atom+xml;type=entry" title="Category" href="Foods(0)/Category" />' +
+ ' <category term="DataJS.Tests.V2.Food" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />' +
+ ' <content type="application/xml">' +
+ ' <m:properties>' +
+ ' <d:FoodID m:type="Edm.Int32">0</d:FoodID>' +
+ ' <d:Name>flour</d:Name>' +
+ ' <d:ServingSize m:type="Edm.Decimal">1</d:ServingSize>' +
+ ' <d:MeasurementUnit>Cup</d:MeasurementUnit>' +
+ ' <d:ProteinGrams m:type="Edm.Byte">3</d:ProteinGrams>' +
+ ' <d:FatGrams m:type="Edm.Int16">1</d:FatGrams>' +
+ ' <d:CarbohydrateGrams m:type="Edm.Int32">20</d:CarbohydrateGrams>' +
+ ' <d:CaloriesPerServing m:type="Edm.Int64">140</d:CaloriesPerServing>' +
+ ' <d:IsAvailable m:type="Edm.Boolean">true</d:IsAvailable>' +
+ ' <d:ExpirationDate m:type="Edm.DateTime">2010-12-25T12:00:00</d:ExpirationDate>' +
+ ' <d:ItemGUID m:type="Edm.Guid">27272727-2727-2727-2727-272727272727</d:ItemGUID>' +
+ ' <d:Weight m:type="Edm.Single">10</d:Weight>' +
+ ' <d:AvailableUnits m:type="Edm.SByte">1</d:AvailableUnits>' +
+ ' <d:Packaging m:type="DataJS.Tests.V2.Package">' +
+ ' <d:Type m:null="true" />' +
+ ' <d:Color></d:Color>' +
+ ' <d:NumberPerPackage m:type="Edm.Int32">2147483647</d:NumberPerPackage>' +
+ ' <d:RequiresRefridgeration m:type="Edm.Boolean">false</d:RequiresRefridgeration>' +
+ ' <d:ShipDate m:type="Edm.DateTime">0001-01-01T00:00:00</d:ShipDate>' +
+ ' <d:PackageDimensions m:type="DataJS.Tests.V2.Dimensions">' +
+ ' <d:Length m:type="Edm.Decimal">79228162514264337593543950335</d:Length>' +
+ ' <d:Height m:type="Edm.Int16">32767</d:Height>' +
+ ' <d:Width m:type="Edm.Int64">9223372036854775807</d:Width>' +
+ ' <d:Volume m:type="Edm.Double">1.7976931348623157E+308</d:Volume>' +
+ ' </d:PackageDimensions>' +
+ ' </d:Packaging>' +
+ ' </m:properties>' +
+ ' </content>' +
+ ' <cooked:cooked cooked:length="2" cooked:height="1" cooked:width="3" xmlns:cooked="http://www.example.org/cooked/">' +
+ ' <cooked:volume>6</cooked:volume>' +
+ ' </cooked:cooked>' +
+ ' <pr:price pr:value="0.19999" xmlns:pr="http://www.example.org/price/"></pr:price>' +
+ '</entry>';
+
+ var metadata = parseMetadataHelper(foodServiceV2MetadataText);
+ var response = { body: payload, headers: { "Content-Type": "application/atom+xml"} };
+ OData.atomHandler.read(response, { metadata: metadata });
+
+ djstest.assert(response.data !== null, "response.data !== null");
+ djstest.assertAreEqual(response.data.__metadata.type, "DataJS.Tests.V2.Food", "types match");
+ djstest.assertAreEqual(response.data.UnitPrice, 0.19999, "Price is as expected");
+ djstest.assertAreEqual(response.data.__metadata.properties.UnitPrice.type, "Edm.Double", "Price was marked as a double");
+
+ djstest.assertAreEqual(response.data.CookedSize.__metadata.properties.Length.type, "Edm.Decimal", "CookedSize.Length was marked as a decimal");
+
+ // When properties are marked on complex type metadata, this assertion will be true as well.
+ // djstest.assertAreEqual(response.data.Packaging.__metadata.Type.type, "Edm.String", "Packaging type was marked as a string");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function parseNullInlineTest() {
+ // Shorter version of:
+ // OData.read("/tests/endpoints/FoodStoreDataService.svc/Foods?$expand=Category&$filter=Category eq null", function(data, response) {
+
+ var body = '' +
+ '<feed xml:base="http://localhost/tests/endpoints/FoodStoreDataService.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">' +
+ ' <entry>' +
+ ' <id>http://localhost/tests/endpoints/FoodStoreDataService.svc/Foods(2)</id>' +
+ ' <link rel="edit" title="Food" href="Foods(2)" />' +
+ ' <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Category" type="application/atom+xml;type=entry" title="Category" href="Foods(2)/Category">' +
+ ' <m:inline />' +
+ ' </link>' +
+ ' <category term="DataJS.Tests.Food" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />' +
+ ' <content type="application/xml">' +
+ ' <m:properties>' +
+ ' <d:FoodID m:type="Edm.Int32">2</d:FoodID>' +
+ ' <d:Name>1 Chicken Egg</d:Name>' +
+ ' <d:UnitPrice m:type="Edm.Double">0.55</d:UnitPrice>' +
+ ' </m:properties>' +
+ ' </content>' +
+ ' </entry>' +
+ '</feed>';
+ var response = { body: body, headers: { "Content-Type": "application/atom+xml"} };
+ OData.atomHandler.read(response, {});
+ var data = response.data;
+ var r = data.results[0];
+ djstest.assertAreEqual(r.Category, null, "r.Category is null as an empty inline entry");
+ djstest.assertAreEqual(r.FoodID, 2, "r.FoodID read correctly");
+ djstest.assertAreEqual(r.__metadata.properties.Category.extensions[0].name, "title", "Category title extension parsed");
+ djstest.assertAreEqual(r.__metadata.properties.Category.extensions[0].value, "Category", "Category title value parsed");
+ djstest.done();
+ });
+
+ djstest.addTest(function serializeEpmTest() {
+ var metadata = parseMetadataHelper(foodServiceV2MetadataText);
+ var data = { __metadata: { type: "DataJS.Tests.V2.Food" }, FoodID: 123, Name: "name", CookedSize: { Length: 1, Height: 2, Width: 3, Volume: 4} };
+ var request = { data: data, headers: { "Content-Type": "application/atom+xml"} };
+ OData.atomHandler.write(request, { metadata: metadata });
+ djstest.assert(request.body.indexOf("CookedSize") === -1, "CookedSize element is missing from payload");
+ djstest.assert(request.body.indexOf("length=") !== -1, "length is available as a mapped attribute");
+ djstest.assert(request.body.indexOf("height=") !== -1, "height is available as a mapped attribute");
+ djstest.assert(request.body.indexOf("width=") !== -1, "width is available as a mapped attribute");
+ djstest.assert(request.body.indexOf("volume>") !== -1, "volume is available as a mapped element");
+ djstest.done();
+ });
+
+ djstest.addTest(function writeNullComplexTypeTest() {
+
+ // Verify that the server can be updated to set a complex value to null.
+ var foodSetUrl = "./endpoints/FoodStoreDataServiceV2.svc/Foods";
+ resetFoodData();
+
+ // Without metadata, this will fail because the server version won't be set to 2.0.
+ var metadata = parseMetadataHelper(foodServiceV2MetadataText);
+ OData.read(foodSetUrl + "?$top=1", function (data) {
+ var item = data.results[0];
+ djstest.assert(item.Packaging, "item.Packaging is not null");
+ item.Packaging = null;
+
+ // The server will reject links for PUT operations.
+ delete item.Category;
+
+ OData.request({ method: "PUT", requestUri: item.__metadata.uri, data: item, headers: { "Content-Type": "application/atom+xml"} }, function (data) {
+ // Re-read the item.
+ OData.read(item.__metadata.uri, function (data) {
+ djstest.assert(data, "data was read successfully again");
+ djstest.assert(!data.Packaging, "!data.Packaging");
+ resetFoodData();
+ djstest.done();
+ }, djstest.failAndDoneCallback("Failed to read back food.", resetFoodData));
+ }, djstest.failAndDoneCallback("Failed to write food"), null, null, metadata);
+ }, djstest.failAndDoneCallback("Failed to read food"), null, null, metadata);
+ });
+
+ djstest.addTest(function writeNonNullLinkTest() {
+ // Verify that the server can be updated to set a link to null.
+ resetFoodData();
+ var foodSetUrl = "./endpoints/FoodStoreDataServiceV2.svc/Foods";
+ var metadata = parseMetadataHelper(foodServiceV2MetadataText);
+ OData.read(foodSetUrl + "?$top=1", function (data) {
+ var item = data.results[0];
+
+ // Turn this into something different.
+ delete item.__metadata.uri;
+ item.FoodID = 1001;
+
+ OData.request({ method: "POST", requestUri: foodSetUrl, data: item, headers: { "Content-Type": "application/atom+xml"} }, function (data) {
+ // Re-read the item.
+ OData.read(data.__metadata.uri + "?$expand=Category", function (data) {
+ djstest.assert(data, "data was read successfully again");
+ djstest.assert(data.Category, "data.Category");
+ djstest.assert(data.Category.Name, "data.Category.Name");
+ resetFoodData();
+ djstest.done();
+ }, djstest.failAndDoneCallback("Failed to read back food.", resetFoodData));
+ }, djstest.failAndDoneCallback("Failed to add modified food"), null, null, metadata);
+ }, djstest.failAndDoneCallback("Failed to read food"), null, null, metadata);
+ });
+
+ djstest.addTest(function writeNullLinkTest() {
+ // Verify that the server can be updated to set a link to null.
+ resetFoodData();
+ var foodSetUrl = "./endpoints/FoodStoreDataServiceV2.svc/Foods";
+ var metadata = parseMetadataHelper(foodServiceV2MetadataText);
+ OData.read(foodSetUrl + "?$top=1", function (data) {
+ var item = data.results[0];
+
+ // Turn this into something different.
+ delete item.__metadata.uri;
+ item.FoodID = 1001;
+ item.Category = null;
+
+ OData.request({ method: "POST", requestUri: foodSetUrl, data: item, headers: { "Content-Type": "application/atom+xml"} }, function (data) {
+ // Re-read the item.
+ OData.read(data.__metadata.uri + "?$expand=Category", function (data) {
+ djstest.assert(data, "data was read successfully again");
+ djstest.assert(!data.Category, "data.Category");
+ resetFoodData();
+ djstest.done();
+ }, djstest.failAndDoneCallback("Failed to read back food.", resetFoodData));
+ }, djstest.failAndDoneCallback("Failed to add modified food"), null, null, metadata);
+ }, djstest.failAndDoneCallback("Failed to read food"), null, null, metadata);
+ });
+
+ // DATAJS INTERNAL START
+ djstest.addTest(function lookupEntityTypeInSchemaTest() {
+ var schemaEmpty = {};
+ var schemaZero = {
+ namespace: "Zero",
+ entityType: [
+ { name: "Genre" },
+ { name: "Language" }
+ ]
+ };
+ var schemaOne = {
+ namespace: "One",
+ entityType: [
+ { name: "Genre1" },
+ { name: "Language1" }
+ ]
+ };
+ var edmx = { dataServices: { schema: [schemaEmpty, schemaZero, schemaOne]} };
+
+ var lookupEntityTypeInSchema = function (name, schema) {
+ return OData.lookupInMetadata(name, schema, "entityType");
+ };
+
+ djstest.assertAreEqual(
+ lookupEntityTypeInSchema("Zero.Genre"),
+ null, "Expected null for missing metadata");
+ djstest.assertAreEqual(
+ lookupEntityTypeInSchema("", schemaEmpty),
+ null, "Expected null for empty type name");
+ djstest.assertAreEqual(
+ lookupEntityTypeInSchema("FooWar", schemaEmpty),
+ null, "Expected null for mismatched name/namespace");
+ djstest.assertAreEqual(
+ lookupEntityTypeInSchema("Zero", schemaZero),
+ null, "Expected null for unqualified type name");
+ djstest.assertAreEqual(
+ lookupEntityTypeInSchema("Zero.Something", schemaZero),
+ null, "Expected null for mismatched type name");
+ djstest.assertAreEqualDeep(
+ lookupEntityTypeInSchema("Zero.Genre", schemaZero),
+ { name: "Genre" }, "Found type by full name");
+
+ djstest.assertAreEqual(
+ lookupEntityTypeInSchema("Zero.Something", edmx),
+ null, "Expected null for mismatched type name in edmx");
+ djstest.assertAreEqualDeep(
+ lookupEntityTypeInSchema("Zero.Genre", edmx),
+ { name: "Genre" }, "Found type by full name in edmx");
+ djstest.assertAreEqualDeep(
+ lookupEntityTypeInSchema("One.Genre1", edmx),
+ { name: "Genre1" }, "Found type by full name in edmx");
+
+ djstest.assertAreEqual(
+ OData.lookupInMetadata("One.Genre1", edmx, "complexType"),
+ null, "Expected null for a complex type lookup of an entity type.");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function testLookupEntityType() {
+ var schemaZero = {
+ namespace: "Zero",
+ entityType: [
+ { name: "Genre" },
+ { name: "Language" }
+ ]
+ };
+ var schemaOne = {
+ namespace: "One",
+ entityType: [
+ { name: "Genre1" },
+ { name: "Language1" }
+ ]
+ };
+ var schemaTwo = {
+ namespace: "Two",
+ entityType: [
+ { name: "Genre2" },
+ { name: "Language2" }
+ ]
+ };
+ var edmx = { dataServices: { schema: [schemaZero, schemaOne]} };
+ var metadata = [edmx, schemaTwo];
+
+ djstest.assertAreEqual(
+ OData.lookupEntityType("Zero.Something", metadata),
+ null, "Expected null for mismatched type name in metadata");
+ djstest.assertAreEqualDeep(
+ OData.lookupEntityType("Zero.Genre", null),
+ null, "Expected null for missing metadata");
+ djstest.assertAreEqualDeep(
+ OData.lookupEntityType(null, metadata),
+ null, "Expected null for missing name");
+ djstest.assertAreEqualDeep(
+ OData.lookupEntityType("Zero.Genre", metadata),
+ { name: "Genre" }, "Found type by full name in metadata");
+ djstest.assertAreEqualDeep(
+ OData.lookupEntityType("One.Genre1", metadata),
+ { name: "Genre1" }, "Found type by full name in metadata");
+ djstest.assertAreEqualDeep(
+ OData.lookupEntityType("One.Genre1", edmx),
+ { name: "Genre1" }, "Found type by full name in edmx");
+ djstest.assertAreEqualDeep(
+ OData.lookupEntityType("Two.Genre2", metadata),
+ { name: "Genre2" }, "Found type by full name in metadata");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function testParseSimpleServiceDocument() {
+ var serviceDocString = "\
+ <service xml:base=\"http://services.odata.org/OData/OData.svc/\" \r\n\
+ xmlns:atom=\"http://www.w3.org/2005/Atom\" \r\n\
+ xmlns:app=\"http://www.w3.org/2007/app\" \r\n\
+ xmlns=\"http://www.w3.org/2007/app\">\r\n\
+ <workspace>\r\n\
+ <atom:title>Default</atom:title> \r\n\
+ <collection href=\"Products\">\r\n\
+ <atom:title>Products</atom:title> \r\n\
+ </collection>\r\n\
+ <collection href=\"Categories\">\r\n\
+ <atom:title>Categories</atom:title> \r\n\
+ </collection>\r\n\
+ <collection href=\"Suppliers\">\r\n\
+ <atom:title>Suppliers</atom:title> \r\n\
+ </collection>\r\n\
+ </workspace>\r\n\
+ </service>\r\n";
+
+ var serviceDoc = OData.atomParser(OData.atomHandler, serviceDocString, {});
+
+ djstest.assertAreEqual(serviceDoc.workspaces.length, 1, "Incorrect number of workspaces");
+
+ var workspace = serviceDoc.workspaces[0];
+ djstest.assertAreEqual(workspace.title, "Default", "Incorrect service doc title");
+
+ var expectedCollections = [
+ { expectedHref: "http://services.odata.org/OData/OData.svc/Products", expectedTitle: "Products" },
+ { expectedHref: "http://services.odata.org/OData/OData.svc/Categories", expectedTitle: "Categories" },
+ { expectedHref: "http://services.odata.org/OData/OData.svc/Suppliers", expectedTitle: "Suppliers" }
+ ];
+
+ djstest.assertAreEqual(workspace.collections.length, expectedCollections.length, "Incorrect number of collections in workspace");
+
+ var i, len;
+ for (i = 0, len = expectedCollections.length; i < len; i++) {
+ djstest.assertAreEqual(workspace.collections[i].href, expectedCollections[i].expectedHref, "Incorrect href on collection");
+ djstest.assertAreEqual(workspace.collections[i].title, expectedCollections[i].expectedTitle, "Incorrect title on collection");
+ }
+
+ djstest.done();
+ });
+
+ djstest.addTest(function testServiceDocMustHaveAtLeastOneWorkspaceElement() {
+ // Construct a service doc with no workspaces and verify that the parser throws.
+ var serviceDocString = "\
+ <service xml:base=\"http://services.odata.org/OData/OData.svc/\" \r\n\
+ xmlns:atom=\"http://www.w3.org/2005/Atom\" \r\n\
+ xmlns:app=\"http://www.w3.org/2007/app\" \r\n\
+ xmlns=\"http://www.w3.org/2007/app\">\r\n\
+ </service>\r\n";
+
+ djstest.expectException(function () {
+ var serviceDoc = OData.atomParser(OData.atomHandler, serviceDocString, {});
+ }, "Parsing service doc with no workspaces");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function testServiceDocMayHaveMoreThanOneWorkspaceElement() {
+ var serviceDocString = "\
+ <service xml:base=\"http://services.odata.org/OData/OData.svc/\" \r\n\
+ xmlns:atom=\"http://www.w3.org/2005/Atom\" \r\n\
+ xmlns:app=\"http://www.w3.org/2007/app\" \r\n\
+ xmlns=\"http://www.w3.org/2007/app\">\r\n\
+ <workspace>\r\n\
+ <atom:title>Default</atom:title> \r\n\
+ <collection href=\"Products\">\r\n\
+ <atom:title>Products</atom:title> \r\n\
+ </collection>\r\n\
+ <collection href=\"Categories\">\r\n\
+ <atom:title>Categories</atom:title> \r\n\
+ </collection>\r\n\
+ <collection href=\"Suppliers\">\r\n\
+ <atom:title>Suppliers</atom:title> \r\n\
+ </collection>\r\n\
+ </workspace>\r\n\
+ <workspace>\r\n\
+ <atom:title>Second Workspace</atom:title> \r\n\
+ <collection href=\"Collection1\">\r\n\
+ <atom:title>Collection Number 1</atom:title> \r\n\
+ </collection>\r\n\
+ <collection href=\"Collection2\">\r\n\
+ <atom:title>Collection Number 2</atom:title> \r\n\
+ </collection>\r\n\
+ </workspace>\r\n\
+ </service>\r\n";
+
+ var serviceDoc = OData.atomParser(OData.atomHandler, serviceDocString, {});
+
+ djstest.assertAreEqual(serviceDoc.workspaces.length, 2, "Incorrect number of workspaces");
+
+ var workspace = serviceDoc.workspaces[0];
+ djstest.assertAreEqual(workspace.title, "Default", "Incorrect service doc title");
+
+ var expectedCollections;
+ expectedCollections = [
+ { expectedHref: "http://services.odata.org/OData/OData.svc/Products", expectedTitle: "Products" },
+ { expectedHref: "http://services.odata.org/OData/OData.svc/Categories", expectedTitle: "Categories" },
+ { expectedHref: "http://services.odata.org/OData/OData.svc/Suppliers", expectedTitle: "Suppliers" }
+ ];
+
+ djstest.assertAreEqual(workspace.collections.length, expectedCollections.length, "Incorrect number of collections in workspace");
+
+ var i, len;
+ for (i = 0, len = expectedCollections.length; i < len; i++) {
+ djstest.assertAreEqual(workspace.collections[i].href, expectedCollections[i].expectedHref, "Incorrect href on collection");
+ djstest.assertAreEqual(workspace.collections[i].title, expectedCollections[i].expectedTitle, "Incorrect title on collection");
+ }
+
+ workspace = serviceDoc.workspaces[1];
+ djstest.assertAreEqual(workspace.title, "Second Workspace", "Incorrect service doc title");
+
+ expectedCollections = [
+ { expectedHref: "http://services.odata.org/OData/OData.svc/Collection1", expectedTitle: "Collection Number 1" },
+ { expectedHref: "http://services.odata.org/OData/OData.svc/Collection2", expectedTitle: "Collection Number 2" }
+ ];
+
+ djstest.assertAreEqual(workspace.collections.length, expectedCollections.length, "Incorrect number of collections in workspace");
+
+ for (i = 0, len = expectedCollections.length; i < len; i++) {
+ djstest.assertAreEqual(workspace.collections[i].href, expectedCollections[i].expectedHref, "Incorrect href on collection");
+ djstest.assertAreEqual(workspace.collections[i].title, expectedCollections[i].expectedTitle, "Incorrect title on collection");
+ }
+
+ djstest.done();
+ });
+
+ djstest.addTest(function testCollectionTitlesAndHrefsMayBeDifferent() {
+ var serviceDocString = "\
+ <service xml:base=\"http://services.odata.org/OData/OData.svc/\" \r\n\
+ xmlns:atom=\"http://www.w3.org/2005/Atom\" \r\n\
+ xmlns:app=\"http://www.w3.org/2007/app\" \r\n\
+ xmlns=\"http://www.w3.org/2007/app\">\r\n\
+ <workspace>\r\n\
+ <atom:title>Default</atom:title> \r\n\
+ <collection href=\"abc\">\r\n\
+ <atom:title>xyz</atom:title> \r\n\
+ </collection>\r\n\
+ <collection href=\"blah\">\r\n\
+ <atom:title>foo</atom:title> \r\n\
+ </collection>\r\n\
+ </workspace>\r\n\
+ </service>\r\n";
+
+ var serviceDoc = OData.atomParser(OData.atomHandler, serviceDocString, {});
+
+ djstest.assertAreEqual(serviceDoc.workspaces.length, 1, "Incorrect number of workspaces");
+
+ var workspace = serviceDoc.workspaces[0];
+ djstest.assertAreEqual(workspace.title, "Default", "Incorrect service doc title");
+
+ var expectedCollections = [
+ { expectedHref: "http://services.odata.org/OData/OData.svc/abc", expectedTitle: "xyz" },
+ { expectedHref: "http://services.odata.org/OData/OData.svc/blah", expectedTitle: "foo" }
+ ];
+
+ djstest.assertAreEqual(workspace.collections.length, expectedCollections.length, "Incorrect number of collections in workspace");
+
+ var i, len;
+ for (i = 0, len = expectedCollections.length; i < len; i++) {
+ djstest.assertAreEqual(workspace.collections[i].href, expectedCollections[i].expectedHref, "Incorrect href on collection");
+ djstest.assertAreEqual(workspace.collections[i].title, expectedCollections[i].expectedTitle, "Incorrect title on collection");
+ }
+
+ djstest.done();
+ });
+
+ djstest.addTest(function testParserShouldTreatMissingWorkspaceTitleAsBlank() {
+ // Per RFC 5023 Section 8.3.2.1, the workspace element MUST have a title but
+ // in the interests of being permissive, we should treat this as blank.
+ var serviceDocString = "\
+ <service xml:base=\"http://services.odata.org/OData/OData.svc/\" \r\n\
+ xmlns:atom=\"http://www.w3.org/2005/Atom\" \r\n\
+ xmlns:app=\"http://www.w3.org/2007/app\" \r\n\
+ xmlns=\"http://www.w3.org/2007/app\">\r\n\
+ <workspace>\r\n\
+ <!-- No workspace title element -->\r\n\
+ <collection href=\"Products\">\r\n\
+ <atom:title>Products</atom:title> \r\n\
+ </collection>\r\n\
+ <collection href=\"Categories\">\r\n\
+ <atom:title>Categories</atom:title> \r\n\
+ </collection>\r\n\
+ <collection href=\"Suppliers\">\r\n\
+ <atom:title>Suppliers</atom:title> \r\n\
+ </collection>\r\n\
+ </workspace>\r\n\
+ </service>\r\n";
+
+ var serviceDoc = OData.atomParser(OData.atomHandler, serviceDocString, {});
+
+ djstest.assertAreEqual(serviceDoc.workspaces.length, 1, "Incorrect number of workspaces");
+
+ var workspace = serviceDoc.workspaces[0];
+ djstest.assertAreEqual(workspace.title, "", "Incorrect service doc title");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function testWorkspaceMayHaveNoCollections() {
+ var serviceDocString = "\
+ <service xml:base=\"http://services.odata.org/OData/OData.svc/\" \r\n\
+ xmlns:atom=\"http://www.w3.org/2005/Atom\" \r\n\
+ xmlns:app=\"http://www.w3.org/2007/app\" \r\n\
+ xmlns=\"http://www.w3.org/2007/app\">\r\n\
+ <workspace>\r\n\
+ <atom:title>Default</atom:title> \r\n\
+ </workspace>\r\n\
+ </service>\r\n";
+
+ var serviceDoc = OData.atomParser(OData.atomHandler, serviceDocString, {});
+
+ djstest.assertAreEqual(serviceDoc.workspaces.length, 1, "Incorrect number of workspaces");
+
+ var workspace = serviceDoc.workspaces[0];
+ var expectedCollections = [];
+
+ djstest.assertAreEqual(workspace.collections.length, expectedCollections.length, "Incorrect number of collections in workspace");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function testCollectionMustHaveTitleElement() {
+ var serviceDocString = "\
+ <service xml:base=\"http://services.odata.org/OData/OData.svc/\" \r\n\
+ xmlns:atom=\"http://www.w3.org/2005/Atom\" \r\n\
+ xmlns:app=\"http://www.w3.org/2007/app\" \r\n\
+ xmlns=\"http://www.w3.org/2007/app\">\r\n\
+ <workspace>\r\n\
+ <atom:title>Default</atom:title> \r\n\
+ <collection href=\"Products\">\r\n\
+ <!-- No title element -->\r\n\
+ </collection>\r\n\
+ </workspace>\r\n\
+ </service>\r\n";
+
+ djstest.expectException(function () {
+ var serviceDoc = OData.atomParser(OData.atomHandler, serviceDocString, {});
+ }, "Parsing service doc with a collection with no title element");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function testCollectionMustHaveHrefAttribute() {
+ var serviceDocString = "\
+ <service xml:base=\"http://services.odata.org/OData/OData.svc/\" \r\n\
+ xmlns:atom=\"http://www.w3.org/2005/Atom\" \r\n\
+ xmlns:app=\"http://www.w3.org/2007/app\" \r\n\
+ xmlns=\"http://www.w3.org/2007/app\">\r\n\
+ <workspace>\r\n\
+ <atom:title>Default</atom:title> \r\n\
+ <!-- href attribute missing below --> \r\n\
+ <collection>\r\n\
+ <atom:title>Products</atom:title> \r\n\
+ </collection>\r\n\
+ </workspace>\r\n\
+ </service>\r\n";
+
+ djstest.expectException(function () {
+ var serviceDoc = OData.atomParser(OData.atomHandler, serviceDocString, {});
+ }, "Parsing service doc with a collection with no href attribute");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadDocumentTest() {
+ var emptyServiceString = "\
+ <service xml:base=\"http://services.odata.org/OData/OData.svc/\" \r\n\
+ xmlns:atom=\"http://www.w3.org/2005/Atom\" \r\n\
+ xmlns:app=\"http://www.w3.org/2007/app\" \r\n\
+ xmlns=\"http://www.w3.org/2007/app\">\r\n\
+ <workspace>\r\n\
+ <atom:title>empty service</atom:title> \r\n\
+ </workspace>\r\n\
+ </service>\r\n";
+
+ var emptyFeedString = "\
+ <feed xml:base=\'http://services.odata.org/OData/OData.svc/\' \r\n\
+ xmlns:app=\'http://www.w3.org/2007/app\' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\'> \r\n\
+ <id>feed id</id> \r\n\
+ <title>empty feed</title> \r\n\
+ </feed> \r\n";
+
+ var emptyEntryString = "\
+ <entry xml:base=\'http://services.odata.org/OData/OData.svc/\' \r\n\
+ xmlns:app=\'http://www.w3.org/2007/app\' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\'> \r\n\
+ <id>entry id</id> \r\n\
+ <title>empty entry</title> \r\n\
+ </entry> \r\n";
+
+ var nonAtomString = "\
+ <notAtom xml:base=\'http://services.odata.org/OData/OData.svc/\' \r\n\
+ xmlns:app=\'http://www.w3.org/2007/app\' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\'> \r\n\
+ <id>entry id</id> \r\n\
+ <title>empty entry</title> \r\n\
+ </notAtom> \r\n";
+
+ var service = OData.atomReadDocument(datajs.xmlParse(emptyServiceString).documentElement);
+ var feed = OData.atomReadDocument(datajs.xmlParse(emptyFeedString).documentElement);
+ var entry = OData.atomReadDocument(datajs.xmlParse(emptyEntryString).documentElement);
+ var nonAtom = OData.atomReadDocument(datajs.xmlParse(nonAtomString).documentElement);
+
+ djstest.assert(service && service.workspaces.length === 1, "atomReadDocument deserialized a service document");
+ djstest.assert(feed && feed.results.length === 0, "atomReadDocument deserialized a feed document");
+ djstest.assert(entry && !entry.results && entry.__metadata.uri === "http://services.odata.org/OData/OData.svc/entry id", "atomReadDocument deserialized a entry document");
+ djstest.assertAreEqual(nonAtom, undefined, "atomReadDocument returns undefined with non Atom input");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadFeedV1Test() {
+ var simpleFeedString = "\
+ <feed xml:base=\'http://services.odata.org/OData/OData.svc/\' \r\n\
+ xmlns:app=\'http://www.w3.org/2007/app\' \r\n\
+ xmlns:m=\'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\'> \r\n\
+ <id>feed id</id> \r\n\
+ <title>test feed</title> \r\n\
+ <entry> \r\n\
+ <id>entry id</id> \r\n\
+ <title>empty entry</title> \r\n\
+ </entry> \r\n\
+ </feed> \r\n";
+
+ var expectedFeed = {
+ __metadata: {
+ uri: "http://services.odata.org/OData/OData.svc/feed id",
+ uri_extensions: [],
+ title: "test feed",
+ title_extensions: [],
+ feed_extensions: []
+ },
+ results: [
+ { __metadata: {
+ uri: "http://services.odata.org/OData/OData.svc/entry id",
+ uri_extensions: []
+ }
+ }
+ ]
+ };
+
+ var feed = OData.atomReadFeed(datajs.xmlParse(simpleFeedString).documentElement);
+
+ djstest.assert(feed, "atomReadFeed didn't return a feed object for a V1 payload");
+ djstest.assertAreEqualDeep(feed, expectedFeed, "atomReadFeed didn't return the expected feed");
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadFeedV2Test() {
+ var simpleFeedString = "\
+ <feed xml:base=\'http://services.odata.org/OData/OData.svc/\' \r\n\
+ xmlns:app=\'http://www.w3.org/2007/app\' \r\n\
+ xmlns:m=\'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\'> \r\n\
+ <id>feed id</id> \r\n\
+ <title>test feed</title> \r\n\
+ <m:count>2</m:count> \r\n\
+ <entry> \r\n\
+ <id>entry id</id> \r\n\
+ <title>empty entry</title> \r\n\
+ </entry> \r\n\
+ <link rel=\'next\' href=\'http://nexturi\'/> \r\n\
+ </feed> \r\n";
+
+ var expectedFeed = {
+ __count: 2,
+ __metadata: {
+ uri: "http://services.odata.org/OData/OData.svc/feed id",
+ uri_extensions: [],
+ title: "test feed",
+ title_extensions: [],
+ feed_extensions: [],
+ next_extensions: []
+ },
+ __next: "http://nexturi",
+ results: [
+ { __metadata: {
+ uri: "http://services.odata.org/OData/OData.svc/entry id",
+ uri_extensions: []
+ }
+ }
+ ]
+ };
+
+ var feed = OData.atomReadFeed(datajs.xmlParse(simpleFeedString).documentElement);
+
+ djstest.assert(feed, "atomReadFeed didn't return a feed object for a V2 payload");
+ djstest.assertAreEqualDeep(feed, expectedFeed, "atomReadFeed didn't return the expected feed");
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadFeedWithActionsAndFunctionsTest() {
+ var feed = "\r\n\
+ <feed xml:base='http://services.odata.org/OData/OData.svc/' \r\n\
+ xmlns:app='http://www.w3.org/2007/app' \r\n\
+ xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' \r\n\
+ xmlns:me='http://myExtensions' \r\n\
+ xmlns='http://www.w3.org/2005/Atom'> \r\n\
+ <id>feed id</id> \r\n\
+ <title>test feed</title> \r\n\
+ <m:action metadata='#EntityContainer.Action1' title='Action1' target='http://service/entities(0)/action' /> \r\n\
+ <m:action metadata='#EntityContainer.Action2' title='Action2' target='entities(0)/action2'/> \r\n\
+ <m:action metadata='http://someService/$metadata#Container.Action1' title='Action1' target='http://someService/action' /> \r\n\
+ <m:function metadata='#EntityContainer.Function1' title='Function1' target='http://service/entities(0)/function' /> \r\n\
+ <m:function metadata='#EntityContainer.Function2' title='Function2' target='entities(0)/function2' /> \r\n\
+ <m:function metadata='http://someService/$metadata#Container.Function1' title='Function1' target='http://someService/function' /> \r\n\
+ </feed> \r\n";
+
+ var expected = {
+ __metadata: {
+ uri: "http://services.odata.org/OData/OData.svc/feed id",
+ uri_extensions: [],
+ title: "test feed",
+ title_extensions: [],
+ feed_extensions: [],
+ actions: [
+ {
+ metadata: "#EntityContainer.Action1",
+ title: "Action1",
+ target: "http://service/entities(0)/action",
+ extensions: []
+ },
+ {
+ metadata: "#EntityContainer.Action2",
+ title: "Action2",
+ target: "http://services.odata.org/OData/OData.svc/entities(0)/action2",
+ extensions: []
+ },
+ {
+ metadata: "http://someService/$metadata#Container.Action1",
+ title: "Action1",
+ target: "http://someService/action",
+ extensions: []
+ }
+ ],
+ functions: [
+ {
+ metadata: "#EntityContainer.Function1",
+ title: "Function1",
+ target: "http://service/entities(0)/function",
+ extensions: []
+ },
+ {
+ metadata: "#EntityContainer.Function2",
+ title: "Function2",
+ target: "http://services.odata.org/OData/OData.svc/entities(0)/function2",
+ extensions: []
+ },
+ {
+ metadata: "http://someService/$metadata#Container.Function1",
+ title: "Function1",
+ target: "http://someService/function",
+ extensions: []
+ }
+ ]
+ },
+ results: []
+ };
+
+ var response = { headers: { "Content-Type": "application/atom+xml", "DataServiceVersion": "3.0" }, body: feed };
+
+ OData.atomHandler.read(response);
+ djstest.assertAreEqualDeep(response.data, expected, "atomReadEntry didn't return the expected entry object");
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadFeedExtensionsTest() {
+ var feedWithExtensionsString = "\
+ <feed xml:base=\'http://services.odata.org/OData/OData.svc/\' \r\n\
+ xmlns:app=\'http://www.w3.org/2007/app\' \r\n\
+ xmlns:me=\'http://myExtensions' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\' attr1=\'a1\' me:attr2=\'a2\'> \r\n\
+ <me:element1>e1</me:element1> \r\n\
+ <me:element2> \r\n\
+ <me:element21 attr3=\'a3\' me:attr4=\'a4\' >e1</me:element21> \r\n\
+ </me:element2> \r\n\
+ <id>feed id</id> \r\n\
+ <title>test feed</title> \r\n\
+ </feed> \r\n"
+
+ var feed = OData.atomReadFeed(datajs.xmlParse(feedWithExtensionsString).documentElement);
+ djstest.assert(feed, "atomReadFeed didn't return a feed object for a payload with feed extensions");
+ djstest.assertAreEqual(feed.__metadata.feed_extensions.length, 4, "atomReadFeed didn't return the expected number of extensions");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadFeedLinksTest() {
+ var feedLinksString = "\
+ <feed xml:base=\'http://services.odata.org/OData/OData.svc/\' \r\n\
+ xmlns:app=\'http://www.w3.org/2007/app\' \r\n\
+ xmlns:me=\'http://myExtensions\' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\'> \r\n\
+ <link rel=\'next\' href=\'http://nexturi\' me:attr1=\'a1\' attr2=\'a2\'/> \r\n\
+ <link rel=\'self\' href=\'http://selfuri\' me:attr3=\'a1\' attr4=\'a2\'/> \r\n\
+ <link rel=\'alternate\' href=\'http://otheruri\'/> \r\n\
+ </feed> \r\n";
+
+ var root = datajs.xmlParse(feedLinksString).documentElement;
+ var feed = { __metadata: {} };
+ datajs.xmlChildElements(root, function (child) {
+ OData.atomReadFeedLink(child, feed);
+ });
+
+ djstest.assertAreEqual(feed.__next, "http://nexturi", "atomReadFeedLink didn't read the next link element");
+ djstest.assertAreEqual(feed.__metadata.next_extensions.length, 2, "atomReadFeedLink didn't return the expected number of next link extensions");
+ djstest.assertAreEqual(feed.__metadata.self, "http://selfuri", "atomReadFeedLink didn't read the self link element");
+ djstest.assertAreEqual(feed.__metadata.self_extensions.length, 2, "atomReadFeedLink didn't return the expected number of self link extensions");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadLinkTest() {
+ var linkString = "\
+ <link xmlns:me=\'http://myExtensions\' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\' \r\n\
+ rel=\'next\' \r\n\
+ href=\'http://nexturi\' \r\n\
+ type=\'application/atom+xml;type=feed\' \r\n\
+ me:attr1=\'a1\' \r\n\
+ attr2=\'a2\'/> \r\n";
+
+ var link = OData.atomReadLink(datajs.xmlParse(linkString).documentElement);
+
+ djstest.assert(link, "atomReadLink didn't return a link object");
+ djstest.assertAreEqual(link.href, "http://nexturi", "atomReadLink, link object href field has an unexpected value");
+ djstest.assertAreEqual(link.rel, "next", "atomReadLink, link object rel field has an unexpected value");
+ djstest.assertAreEqual(link.type, "application/atom+xml;type=feed", "atomReadLink, link object type field has an unexpected value");
+ djstest.assertAreEqual(link.extensions.length, 2, "atomReadLink, link object extensions doesn't have the expected number of extensions");
+
+ djstest.done();
+
+ });
+
+ djstest.addTest(function atomReadLinkThrowHrefMissingTest() {
+ var linkString = "\
+ <link xmlns:me=\'http://myExtensions\' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\' \r\n\
+ rel=\'next\' \r\n\
+ type=\'application/atom+xml;type=feed\' \r\n\
+ me:attr1=\'a1\' \r\n\
+ attr2=\'a2\'/> \r\n";
+
+
+ var linkRoot = datajs.xmlParse(linkString).documentElement;
+ djstest.expectException(function () {
+ OData.atomReadLink(linkRoot);
+ }, "atomReadLink didn't throw an exception when the link doesn't have the href attribute");
+ djstest.done();
+
+ });
+
+ djstest.addTest(function atomReadExtensionElementTest() {
+ var extensionString = "\
+ <me:ext xmlns:me=\'http://myExtensions\' me:attr1=\'a1\' attr2=\'a2\'> \r\n\
+ <ext>e1</ext> \r\n\
+ </me:ext> \r\n";
+
+ var validateExtension = function (ext, name, namespaceURI, attributeCount, childrenCount, value) {
+ djstest.assertAreEqual(ext.name, name, "atomReadExtensionElement, extension object name field has an unexpected value");
+ djstest.assertAreEqual(ext.namespaceURI, namespaceURI, "atomReadExtensionElement, extension object namespaceURI field has an unexpected value");
+ djstest.assertAreEqual(ext.attributes.length, attributeCount, "atomReadExtensionElement, extension object attributes doesn't have the expected number of attributes");
+ djstest.assertAreEqual(ext.children.length, childrenCount, "atomReadExtensionElement, extension object attributes doesn't have the expected number of children");
+ djstest.assertAreEqual(ext.value, value, "atomReadExtensionElement, extension object value field has an unexpected value");
+ };
+
+ var extension = OData.atomReadExtensionElement(datajs.xmlParse(extensionString).documentElement);
+ validateExtension(extension, "ext", "http://myExtensions", 2, 1);
+
+ extension = extension.children[0];
+ validateExtension(extension, "ext", null, 0, 0, "e1");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadExtensionAttributesTest() {
+ var extensionString = "\
+ <me:ext xmlns:me=\'http://myExtensions\' me:attr1=\'a1\' attr2=\'a2\' /> \r\n";
+
+ var extensionAttributes = OData.atomReadExtensionAttributes(datajs.xmlParse(extensionString).documentElement);
+ djstest.assertAreEqual(extensionAttributes.length, 2, "atomReadExtensionAttribute, returned collection doesn't have the expected number of attributes");
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadExtensionAttributeTest() {
+
+ var tests = {
+ "extension with namespace": {
+ i: '<me:ext xmlns:me="http://myExtensions" me:attr1="a1" />',
+ e: { name: "attr1", namespaceURI: "http://myExtensions", value: "a1" }
+ },
+ "extension without namespace": {
+ i: '<me:ext xmlns:me="http://myExtensions" attr2="a2" />',
+ e: { name: "attr2", namespaceURI: null, value: "a2" }
+ }
+ };
+
+ for (var name in tests) {
+ var test = tests[name];
+ var xmlElement = datajs.xmlParse(test.i).documentElement;
+ var extensions = OData.atomReadExtensionAttributes(xmlElement);
+
+ djstest.assertAreEqualDeep(extensions[0], test.e, name + " - extension object is the expected one");
+ }
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadEntryTest() {
+ var entryString = "\
+ <entry xml:base=\'http://services.odata.org/OData/OData.svc/\' \r\n\
+ xmlns:d2=\'http://schemas.microsoft.com/ado/2007/08/dataservices\' \r\n\
+ xmlns:m2=\'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\' \r\n\
+ xmlns:atom=\'http://www.w3.org/2005/Atom\' \r\n\
+ xmlns:app=\'http://www.w3.org/2007/app\' \r\n\
+ xmlns=\'http://www.w3.org/2005/Atom\'> \r\n\
+ <id>the id</id> \r\n\
+ <category term=\'the type\' \r\n\
+ scheme=\'http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\' /> \r\n\
+ <content type=\'application/xml\'> \r\n\
+ <m2:properties xmlns=\'http://schemas.microsoft.com/ado/2007/08/dataservices\'>\r\n\
+ <Untyped>untyped value</Untyped> \r\n\
+ <Typed m2:type='Edm.Int32'>100</Typed> \r\n\
+ </m2:properties> \r\n\
+ </content> \r\n\
+ <link rel=\'self\' href=\'http://selfuri\' /> \r\n\
+ </entry>\r\n";
+
+ var expectedEntry = {
+ __metadata: {
+ uri: "http://services.odata.org/OData/OData.svc/the id",
+ uri_extensions: [],
+ type: "the type",
+ type_extensions: [],
+ self: "http://selfuri",
+ self_link_extensions: [],
+ properties: {
+ Untyped: {
+ type: "Edm.String",
+ extensions: []
+ },
+ Typed: {
+ type: "Edm.Int32",
+ extensions: []
+ }
+ }
+ },
+ Untyped: "untyped value",
+ Typed: 100
+ };
+
+ var entry = OData.atomReadEntry(datajs.xmlParse(entryString).documentElement);
+
+ djstest.assert(entry, "atomReadEntry didn't return an entry object");
+ djstest.assertAreEqualDeep(entry, expectedEntry);
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadEntryGmlCRSValueTest() {
+ var entryXml =
+ "<entry \r\n\
+ xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' \r\n\
+ xmlns='http://www.w3.org/2005/Atom'> \r\n\
+ <content type='application/xml'> \r\n\
+ <m:properties xmlns='http://schemas.microsoft.com/ado/2007/08/dataservices' \r\n\
+ xmlns:gml='http://www.opengis.net/gml'> \r\n\
+ <PointQualified> \r\n\
+ <gml:Point gml:srsName='http://www.opengis.net/def/crs/EPSG/0/1234'> \r\n\
+ <gml:pos>1 2 3 4</gml:pos> \r\n\
+ </gml:Point> \r\n\
+ </PointQualified> \r\n\
+ <PointUnQualified> \r\n\
+ <gml:Point srsName='http://www.opengis.net/def/crs/EPSG/0/5678'> \r\n\
+ <gml:pos>5 6 7 8</gml:pos> \r\n\
+ </gml:Point> \r\n\
+ </PointUnQualified> \r\n\
+ </m:properties> \r\n\
+ </content> \r\n\
+ </entry>";
+
+ var entry = {
+ __metadata: {
+ properties: {
+ PointQualified: { type: "Edm.Geometry", extensions: [] },
+ PointUnQualified: { type: "Edm.Geometry", extensions: [] }
+ }
+ },
+ PointQualified: {
+ __metadata: { type: "Edm.Geometry" },
+ crs: {
+ type: "name",
+ properties: {
+ name: "EPSG:1234"
+ }
+ },
+ type: "Point",
+ coordinates: [1, 2, 3, 4]
+ },
+ PointUnQualified: {
+ __metadata: { type: "Edm.Geometry" },
+ crs: {
+ type: "name",
+ properties: {
+ name: "EPSG:5678"
+ }
+ },
+ type: "Point",
+ coordinates: [5, 6, 7, 8]
+ }
+ };
+
+ var response = { headers: { "Content-Type": "application/atom+xml" }, body: entryXml };
+
+ OData.atomHandler.read(response);
+ djstest.assertAreEqualDeep(response.data, entry, "Entry was read successfully");
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadEntryGmlUnknownCRSValueThrowsTest() {
+ var entryXml =
+ "<entry \r\n\
+ xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' \r\n\
+ xmlns='http://www.w3.org/2005/Atom'> \r\n\
+ <content type='application/xml'> \r\n\
+ <m:properties xmlns='http://schemas.microsoft.com/ado/2007/08/dataservices' \r\n\
+ xmlns:gml='http://www.opengis.net/gml'> \r\n\
+ <Point> \r\n\
+ <gml:Point srsName='http://www.opengis.net/def/crs/EPSG/1/1234'> \r\n\
+ <gml:pos>1 2 3 4</gml:pos> \r\n\
+ </gml:Point> \r\n\
+ </Point> \r\n\
+ </m:properties> \r\n\
+ </content> \r\n\
+ </entry>";
+
+ var response = { headers: { "Content-Type": "application/atom+xml" }, body: entryXml };
+
+ try {
+ OData.atomHandler.read(response);
+ djstest.fail("An exception was expected");
+ } catch (e) {
+ djstest.assert(e.message.indexOf("Unsupported srs name:") === 0, "Error is the expected one");
+ }
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadEntryGmlPointValueTest() {
+ var entryXml =
+ "<entry \r\n\
+ xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' \r\n\
+ xmlns='http://www.w3.org/2005/Atom'> \r\n\
+ <content type='application/xml'> \r\n\
+ <m:properties xmlns='http://schemas.microsoft.com/ado/2007/08/dataservices' \r\n\
+ xmlns:gml='http://www.opengis.net/gml'> \r\n\
+ <Point> \r\n\
+ <gml:Point> \r\n\
+ <gml:pos>1 2 -3 4</gml:pos> \r\n\
+ </gml:Point> \r\n\
+ </Point> \r\n\
+ <PointWithExtraTags> \r\n\
+ <gml:Point> \r\n\
+ <gml:name>the point</gml:name> \r\n\
+ <gml:pos>5 6 7 8</gml:pos> \r\n\
+ </gml:Point> \r\n\
+ </PointWithExtraTags> \r\n\
+ <EmptyPoint > \r\n\
+ <gml:Point> \r\n\
+ <gml:pos/> \r\n\
+ </gml:Point> \r\n\
+ </EmptyPoint> \r\n\
+ <PointWithSpacesInValue> \r\n\
+ <gml:Point> \r\n\
+ <gml:pos> 8 9 10 11 12 </gml:pos> \r\n\
+ </gml:Point> \r\n\
+ </PointWithSpacesInValue> \r\n\
+ <PointWithSingleValue> \r\n\
+ <gml:Point> \r\n\
+ <gml:pos>13</gml:pos> \r\n\
+ </gml:Point> \r\n\
+ </PointWithSingleValue> \r\n\
+ <PointWithSingleValueAndSpaces> \r\n\
+ <gml:Point> \r\n\
+ <gml:pos> 14 </gml:pos> \r\n\
+ </gml:Point> \r\n\
+ </PointWithSingleValueAndSpaces> \r\n\
+ </m:properties> \r\n\
+ </content> \r\n\
+ </entry>";
+
+ var entry = {
+ __metadata: {
+ properties: {
+ Point: { type: "Edm.Geometry", extensions: [] },
+ PointWithExtraTags: { type: "Edm.Geometry", extensions: [] },
+ EmptyPoint: { type: "Edm.Geometry", extensions: [] },
+ PointWithSpacesInValue: { type: "Edm.Geometry", extensions: [] },
+ PointWithSingleValue: { type: "Edm.Geometry", extensions: [] },
+ PointWithSingleValueAndSpaces: { type: "Edm.Geometry", extensions: [] }
+ }
+ },
+ Point: {
+ __metadata: { type: "Edm.Geometry" },
+ type: "Point",
+ coordinates: [1, 2, -3, 4]
+ },
+ PointWithExtraTags: {
+ __metadata: { type: "Edm.Geometry" },
+ type: "Point",
+ coordinates: [5, 6, 7, 8]
+ },
+ EmptyPoint: {
+ __metadata: { type: "Edm.Geometry" },
+ type: "Point",
+ coordinates: []
+ },
+ PointWithSpacesInValue: {
+ __metadata: { type: "Edm.Geometry" },
+ type: "Point",
+ coordinates: [8, 9, 10, 11, 12]
+ },
+ PointWithSingleValue: {
+ __metadata: { type: "Edm.Geometry" },
+ type: "Point",
+ coordinates: [13]
+ },
+ PointWithSingleValueAndSpaces: {
+ __metadata: { type: "Edm.Geometry" },
+ type: "Point",
+ coordinates: [14]
+ }
+ };
+
+ var response = { headers: { "Content-Type": "application/atom+xml" }, body: entryXml };
+
+ OData.atomHandler.read(response);
+ djstest.assertAreEqualDeep(response.data, entry, "Entry was read successfully");
+ djstest.done();
+ });
+
+ djstest.addTest(function atomReadEntryGmlLineStringValueTest() {
+ var entryXml =
+ "<entry \r\n\
+ xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' \r\n\
+ xmlns='http://www.w3.org/2005/Atom'> \r\n\
+ <content type='application/xml'> \r\n\
+ <m:properties xmlns='http://schemas.microsoft.com/ado/2007/08/dataservices' \r\n\
+ xmlns:gml='http://www.opengis.net/gml'> \r\n\
+ <LineStringExtraTags> \r\n\
+ <gml:LineString> \r\n\
+ <gml:name>the line</gml:name> \r\n\
+ <gml:posList>1.0 2.0 3.0 4.0</gml:posList> \r\n\
+ </gml:LineString> \r\n\
+ </LineStringExtraTags> \r\n\
+ <LineStringPosList> \r\n\
+ <gml:LineString> \r\n\
+ <gml:posList>5.0 6.0 7.0 8.0</gml:posList> \r\n\
+ </gml:LineString> \r\n\
+ </LineStringPosList> \r\n\
+ <LineStringEmptyPosList> \r\n\
+ <gml:LineString> \r\n\
+ <gml:posList/> \r\n\
+ </gml:LineString> \r\n\
+ </LineStringEmptyPosList> \r\n\
+ <LineStringPosAndPoint> \r\n\
+ <gml:LineString> \r\n\
+ <gml:pos>7 8</gml:pos> \r\n\
+ <gml:pointProperty> \r\n\
+ <gml:Point> \r\n\
+ <gml:pos>9 10 11 12</gml:pos> \r\n\
+ </gml:Point> \r\n\
+ </gml:pointProperty>
<TRUNCATED>