From e65bc2becd3ded759b5d5ca42c7d28a631cfc06d Mon Sep 17 00:00:00 2001 From: JamesNK Date: Sat, 8 Sep 2007 08:59:38 +0000 Subject: [PATCH] --- Src/Lib/nunit.framework.dll | Bin 0 -> 77824 bytes Src/Lib/nunit.framework.xml | 5521 +++++++++++++++++ .../AspNetAjaxDateTimeConverterTest.cs | 70 + Src/Newtonsoft.Json.Tests/JsonReaderTest.cs | 220 + .../JsonSerializerTest.cs | 529 ++ Src/Newtonsoft.Json.Tests/JsonWriterTest.cs | 176 + .../Newtonsoft.Json.Tests.csproj | 69 + .../Properties/AssemblyInfo.cs | 35 + .../XmlNodeConverterTest.cs | 342 + Src/Newtonsoft.Json.sln | 44 + .../Converters/AspNetAjaxDateTimeConverter.cs | 59 + .../Converters/HtmlColorConverter.cs | 45 + .../Converters/XmlNodeConverter.cs | 472 ++ Src/Newtonsoft.Json/Identifier.cs | 102 + Src/Newtonsoft.Json/JavaScriptArray.cs | 64 + Src/Newtonsoft.Json/JavaScriptConstructor.cs | 81 + Src/Newtonsoft.Json/JavaScriptConvert.cs | 448 ++ Src/Newtonsoft.Json/JavaScriptObject.cs | 55 + Src/Newtonsoft.Json/JavaScriptParameters.cs | 42 + Src/Newtonsoft.Json/JsonConverter.cs | 48 + .../JsonConverterCollection.cs | 36 + Src/Newtonsoft.Json/JsonHandler.cs | 63 + Src/Newtonsoft.Json/JsonIgnoreAttribute.cs | 36 + Src/Newtonsoft.Json/JsonPropertyAttribute.cs | 21 + Src/Newtonsoft.Json/JsonReader.cs | 897 +++ Src/Newtonsoft.Json/JsonReaderException.cs | 65 + .../JsonSerializationException.cs | 65 + Src/Newtonsoft.Json/JsonSerializer.cs | 649 ++ Src/Newtonsoft.Json/JsonToken.cs | 98 + Src/Newtonsoft.Json/JsonWriter.cs | 732 +++ Src/Newtonsoft.Json/JsonWriterException.cs | 65 + Src/Newtonsoft.Json/MemberMapping.cs | 50 + .../MemberMappingCollection.cs | 42 + Src/Newtonsoft.Json/Newtonsoft.Json.csproj | 84 + .../Properties/AssemblyInfo.cs | 57 + Src/Newtonsoft.Json/StringBuffer.cs | 90 + .../Utilities/CollectionUtils.cs | 419 ++ .../Utilities/JavaScriptUtils.cs | 137 + Src/Newtonsoft.Json/Utilities/MathUtils.cs | 60 + .../Utilities/MiscellaneousUtils.cs | 84 + .../Utilities/ReflectionUtils.cs | 524 ++ Src/Newtonsoft.Json/Utilities/StringUtils.cs | 396 ++ .../Utilities/ValidationUtils.cs | 148 + 43 files changed, 13240 insertions(+) create mode 100644 Src/Lib/nunit.framework.dll create mode 100644 Src/Lib/nunit.framework.xml create mode 100644 Src/Newtonsoft.Json.Tests/AspNetAjaxDateTimeConverterTest.cs create mode 100644 Src/Newtonsoft.Json.Tests/JsonReaderTest.cs create mode 100644 Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs create mode 100644 Src/Newtonsoft.Json.Tests/JsonWriterTest.cs create mode 100644 Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj create mode 100644 Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs create mode 100644 Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs create mode 100644 Src/Newtonsoft.Json.sln create mode 100644 Src/Newtonsoft.Json/Converters/AspNetAjaxDateTimeConverter.cs create mode 100644 Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs create mode 100644 Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs create mode 100644 Src/Newtonsoft.Json/Identifier.cs create mode 100644 Src/Newtonsoft.Json/JavaScriptArray.cs create mode 100644 Src/Newtonsoft.Json/JavaScriptConstructor.cs create mode 100644 Src/Newtonsoft.Json/JavaScriptConvert.cs create mode 100644 Src/Newtonsoft.Json/JavaScriptObject.cs create mode 100644 Src/Newtonsoft.Json/JavaScriptParameters.cs create mode 100644 Src/Newtonsoft.Json/JsonConverter.cs create mode 100644 Src/Newtonsoft.Json/JsonConverterCollection.cs create mode 100644 Src/Newtonsoft.Json/JsonHandler.cs create mode 100644 Src/Newtonsoft.Json/JsonIgnoreAttribute.cs create mode 100644 Src/Newtonsoft.Json/JsonPropertyAttribute.cs create mode 100644 Src/Newtonsoft.Json/JsonReader.cs create mode 100644 Src/Newtonsoft.Json/JsonReaderException.cs create mode 100644 Src/Newtonsoft.Json/JsonSerializationException.cs create mode 100644 Src/Newtonsoft.Json/JsonSerializer.cs create mode 100644 Src/Newtonsoft.Json/JsonToken.cs create mode 100644 Src/Newtonsoft.Json/JsonWriter.cs create mode 100644 Src/Newtonsoft.Json/JsonWriterException.cs create mode 100644 Src/Newtonsoft.Json/MemberMapping.cs create mode 100644 Src/Newtonsoft.Json/MemberMappingCollection.cs create mode 100644 Src/Newtonsoft.Json/Newtonsoft.Json.csproj create mode 100644 Src/Newtonsoft.Json/Properties/AssemblyInfo.cs create mode 100644 Src/Newtonsoft.Json/StringBuffer.cs create mode 100644 Src/Newtonsoft.Json/Utilities/CollectionUtils.cs create mode 100644 Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs create mode 100644 Src/Newtonsoft.Json/Utilities/MathUtils.cs create mode 100644 Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs create mode 100644 Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs create mode 100644 Src/Newtonsoft.Json/Utilities/StringUtils.cs create mode 100644 Src/Newtonsoft.Json/Utilities/ValidationUtils.cs diff --git a/Src/Lib/nunit.framework.dll b/Src/Lib/nunit.framework.dll new file mode 100644 index 0000000000000000000000000000000000000000..de687d97f993541832c4c9cab1822ca8aad51e7c GIT binary patch literal 77824 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 OB#=oUlfWA-f&Tz8tBd&n literal 0 HcmV?d00001 diff --git a/Src/Lib/nunit.framework.xml b/Src/Lib/nunit.framework.xml new file mode 100644 index 00000000..8610cfd9 --- /dev/null +++ b/Src/Lib/nunit.framework.xml @@ -0,0 +1,5521 @@ + + + + nunit.framework + + + + + SubstringConstraint can test whether a string contains + the expected substring. + + + + + The Constraint class is the base of all built-in or + user-defined constraints in NUnit. It provides the operator + overloads used to combine constraints. + + + + + Static UnsetObject used to detect derived constraints + failing to set the actual value. + + + + + If true, all string comparisons will ignore case + + + + + If true, arrays will be treated as collections, allowing + those of different dimensions to be compared + + + + + If non-zero, equality comparisons within the specified + tolerance will succeed. + + + + + IComparer object used in comparisons for some constraints. + + + + + The actual value being tested against a constraint + + + + + Flag the constraint to use a tolerance when determining equality. + Currently only used for doubles and floats. + + Tolerance to be used + Self. + + + + Flag the constraint to use the supplied IComparer object. + + The IComparer object to use. + Self. + + + + Write the failure message to the MessageWriter provided + as an argument. The default implementation simply passes + the constraint and the actual value to the writer, which + then displays the constraint description and the value. + + Constraints that need to provide additional details, + such as where the error occured can override this. + + The MessageWriter on which to display the message + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for success, false for failure + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + Write the actual value for a failing constraint test to a + MessageWriter. The default implementation simply writes + the raw value of actual, leaving it to the writer to + perform any formatting. + + The writer on which the actual value is displayed + + + + This operator creates a constraint that is satisfied only if both + argument constraints are satisfied. + + + + + This operator creates a constraint that is satisfied if either + of the argument constraints is satisfied. + + + + + This operator creates a constraint that is satisfied if the + argument constraint is not satisfied. + + + + + Flag the constraint to ignore case and return self. + + + + + Flag the constraint to compare arrays as collections + and return self. + + + + + Class used to detect any derived constraints + that fail to set the actual value in their + Matches override. + + + + + Initializes a new instance of the class. + + The expected. + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for success, false for failure + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + StartsWithConstraint can test whether a string starts + with an expected substring. + + + + + Initializes a new instance of the class. + + The expected string + + + + Test whether the constraint is matched by the actual value. + This is a template method, which calls the IsMatch method + of the derived class. + + + + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + EndsWithConstraint can test whether a string ends + with an expected substring. + + + + + Initializes a new instance of the class. + + The expected string + + + + Test whether the constraint is matched by the actual value. + This is a template method, which calls the IsMatch method + of the derived class. + + + + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + RegexConstraint can test whether a string matches + the pattern provided. + + + + + Initializes a new instance of the class. + + The pattern. + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for success, false for failure + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + EmptyConstraint tests a whether a string or collection is empty, + postponing the decision about which test is applied until the + type of the actual argument is known. + + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for success, false for failure + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + ConstraintBuilder is used to resolve the Not and All properties, + which serve as prefix operators for constraints. With the addition + of an operand stack, And and Or could be supported, but we have + left them out in favor of a simpler, more type-safe implementation. + Use the & and | operator overloads to combine constraints. + + + + + Implicitly convert ConstraintBuilder to an actual Constraint + at the point where the syntax demands it. + + + + + + + Resolves the chain of constraints using an + EqualConstraint as base. + + + + + Resolves the chain of constraints using a + SameAsConstraint as base. + + + + + Resolves the chain of constraints using a + LessThanConstraint as base. + + + + + Resolves the chain of constraints using a + GreaterThanConstraint as base. + + + + + Resolves the chain of constraints using a + LessThanOrEqualConstraint as base. + + + + + Resolves the chain of constraints using a + LessThanOrEqualConstraint as base. + + + + + Resolves the chain of constraints using a + GreaterThanOrEqualConstraint as base. + + + + + Resolves the chain of constraints using a + GreaterThanOrEqualConstraint as base. + + + + + Resolves the chain of constraints using an + ExactTypeConstraint as base. + + + + + Resolves the chain of constraints using an + InstanceOfTypeConstraint as base. + + + + + Resolves the chain of constraints using an + AssignableFromConstraint as base. + + + + + Resolves the chain of constraints using a + ContainsConstraint as base. This constraint + will, in turn, make use of the appropriate + second-level constraint, depending on the + type of the actual argument. + + + + + Resolves the chain of constraints using a + CollectionContainsConstraint as base. + + The expected object + + + + Resolves the chain of constraints using a + StartsWithConstraint as base. + + + + + Resolves the chain of constraints using a + StringEndingConstraint as base. + + + + + Resolves the chain of constraints using a + StringMatchingConstraint as base. + + + + + Resolves the chain of constraints using a + CollectionEquivalentConstraint as base. + + + + + Resolves the chain of constraints using a + CollectionContainingConstraint as base. + + + + + Resolves the chain of constraints using a + CollectionSubsetConstraint as base. + + + + + Resolves the chain of constraints using a + PropertyConstraint as base + + + + + Resolves the chain of constraints using a + PropertyCOnstraint on Length as base + + + + + + + Resolves the chain of constraints using a + PropertyCOnstraint on Length as base + + + + + + + Modifies the ConstraintBuilder by pushing a Prop operator on the + ops stack and the name of the property on the opnds stack. + + + + + + + Resolve a constraint that has been recognized by applying + any pending operators and returning the resulting Constraint. + + A constraint that incorporates all pending operators + + + + Resolves the chain of constraints using + EqualConstraint(null) as base. + + + + + Resolves the chain of constraints using + EqualConstraint(true) as base. + + + + + Resolves the chain of constraints using + EqualConstraint(false) as base. + + + + + Resolves the chain of constraints using + Is.NaN as base. + + + + + Resolves the chain of constraints using + Is.Empty as base. + + + + + Resolves the chain of constraints using + Is.Unique as base. + + + + + Modifies the ConstraintBuilder by pushing a Not operator on the stack. + + + + + Modifies the ConstraintBuilder by pushing a Not operator on the stack. + + + + + Modifies the ConstraintBuilder by pushing an All operator on the stack. + + + + + Modifies the ConstraintBuilder by pushing a Some operator on the stack. + + + + + Modifies the constraint builder by pushing All and Not operators on the stack + + + + + CollectionConstraint is the abstract base class for + constraints that operate on collections. + + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for success, false for failure + + + + Protected method to be implemented by derived classes + + + + + + + CollectionTally counts (tallies) the number of + occurences of each object in one or more enuerations. + + + + + Construct a CollectionTally object from a collection + + + + + + Remove the counts for a collection from the tally, + so long as their are sufficient items to remove. + The tallies are not permitted to become negative. + + The collection to remove + True if there were enough items to remove, otherwise false + + + + Test whether all the counts are equal to a given value + + The value to be looked for + True if all counts are equal to the value, otherwise false + + + + Get the count of the number of times an object is present in the tally + + + + + UniqueItemsConstraint tests whether all the items in a + collection are unique. + + + + + Apply the item constraint to each item in the collection, + failing if any item fails. + + + + + + + Write a description of this constraint to a MessageWriter + + + + + + CollectionContainsConstraint is used to test whether a collection + contains an expected object as a member. + + + + + Construct a CollectionContainsConstraint + + + + + + Test whether the expected item is contained in the collection + + + + + + + Write a descripton of the constraint to a MessageWriter + + + + + + CollectionEquivalentCOnstraint is used to determine whether two + collections are equivalent. + + + + + Construct a CollectionEquivalentConstraint + + + + + + Test whether two collections are equivalent + + + + + + + Write a description of this constraint to a MessageWriter + + + + + + CollectionSubsetConstraint is used to determine whether + one collection is a subset of another + + + + + Construct a CollectionSubsetConstraint + + The collection that the actual value is expected to be a subset of + + + + Test whether the actual collection is a subset of + the expected collection provided. + + + + + + + Write a description of this constraint to a MessageWriter + + + + + + EqualConstraint is able to compare an actual value with the + expected value provided in its constructor. + + + + + Initializes a new instance of the class. + + The expected value. + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for success, false for failure + + + + Write a failure message. Overridden to provide custom + failure messages for EqualConstraint. + + The MessageWriter to write to + + + + Write description of this constraint + + The MessageWriter to write to + + + + Helper method to compare two arrays + + + + + Display the failure information for two collections that did not match. + + The MessageWriter on which to display + The expected collection. + The actual collection + The depth of this failure in a set of nested collections + + + + Displays a single line showing the types and sizes of the expected + and actual collections or arrays. If both are identical, the value is + only shown once. + + The MessageWriter on which to display + The expected collection or array + The actual collection or array + The indentation level for the message line + + + + Displays a single line showing the point in the expected and actual + arrays at which the comparison failed. If the arrays have different + structures or dimensions, both values are shown. + + The MessageWriter on which to display + The expected array + The actual array + Index of the failure point in the underlying collections + The indentation level for the message line + + + + Abstract base class used for prefixes + + + + + The base constraint + + + + + Construct given a base constraint + + + + + + Set all modifiers applied to the prefix into + the base constraint before matching + + + + + NotConstraint negates the effect of some other constraint + + + + + Initializes a new instance of the class. + + The base constraint to be negated. + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for if the base constraint fails, false if it succeeds + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + Write the actual value for a failing constraint test to a MessageWriter. + + The writer on which the actual value is displayed + + + + AllItemsConstraint applies another constraint to each + item in a collection, succeeding if they all succeed. + + + + + Construct an AllItemsConstraint on top of an existing constraint + + + + + + Apply the item constraint to each item in the collection, + failing if any item fails. + + + + + + + Write a description of this constraint to a MessageWriter + + + + + + SomeItemsConstraint applies another constraint to each + item in a collection, succeeding if any of them succeeds. + + + + + Construct a SomeItemsConstraint on top of an existing constraint + + + + + + Apply the item constraint to each item in the collection, + failing if any item fails. + + + + + + + Write a description of this constraint to a MessageWriter + + + + + + SomeItemsConstraint applies another constraint to each + item in a collection, succeeding if any of them succeeds. + + + + + Construct a SomeItemsConstraint on top of an existing constraint + + + + + + Apply the item constraint to each item in the collection, + failing if any item fails. + + + + + + + Write a description of this constraint to a MessageWriter + + + + + + SameAsConstraint tests whether an object is identical to + the object passed to its constructor + + + + + Initializes a new instance of the class. + + The expected object. + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for success, false for failure + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + TypeConstraint is the abstract base for constraints + that take a Type as their expected value. + + + + + The expected Type used by the constraint + + + + + Construct a TypeConstraint for a given Type + + + + + + Write the actual value for a failing constraint test to a + MessageWriter. TypeCOnstraints override this method to write + the name of the type. + + The writer on which the actual value is displayed + + + + ExactTypeConstraint is used to test that an object + is of the exact type provided in the constructor + + + + + Construct an ExactTypeConstraint for a given Type + + + + + + Test that an object is of the exact type specified + + + + + + + Write the description of this constraint to a MessageWriter + + + + + + InstanceOfTypeConstraint is used to test that an object + is of the same type provided or derived from it. + + + + + Construct an InstanceOfTypeConstraint for the type provided + + + + + + Test whether an object is of the specified type or a derived type + + + + + + + Write a description of this constraint to a MessageWriter + + + + + + AssignableFromConstraint is used to test that an object + can be assigned from a given Type. + + + + + Construct an AssignableFromConstraint for the type provided + + + + + + Test whether an object can be assigned from the specified type + + + + + + + Write a description of this constraint to a MessageWriter + + + + + + Abstract base class for constraints that compare values to + determine if one is greater than, equal to or less than + the other. + + + + + The value against which a comparison is to be made + + + + + If true, less than returns success + + + + + if true, equal returns success + + + + + if true, greater than returns success + + + + + The predicate used as a part of the description + + + + + Initializes a new instance of the class. + + The value against which to make a comparison. + if set to true less succeeds. + if set to true equal succeeds. + if set to true greater succeeds. + String used in describing the constraint. + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for success, false for failure + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + Tests whether a value is greater than the value supplied to its constructor + + + + + Initializes a new instance of the class. + + The expected value. + + + + Tests whether a value is greater than or equal to the value supplied to its constructor + + + + + Initializes a new instance of the class. + + The expected value. + + + + Tests whether a value is less than the value supplied to its constructor + + + + + Initializes a new instance of the class. + + The expected value. + + + + Tests whether a value is less than or equal to the value supplied to its constructor + + + + + Initializes a new instance of the class. + + The expected value. + + + + ContainsConstraint tests a whether a string contains a substring + or a collection contains an object. It postpones the decision of + which test to use until the type of the actual argument is known. + This allows testing whether a string is contained in a collection + or as a substring of another string using the same syntax. + + + + + Initializes a new instance of the class. + + The expected. + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for success, false for failure + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + Summary description for PropertyConstraint. + + + + + Initializes a new instance of the class. + + The name. + The constraint to apply to the property. + + + + Test whether the constraint is satisfied by a given value + + The value to be tested + True for success, false for failure + + + + Write the constraint description to a MessageWriter + + The writer on which the description is displayed + + + + Write the actual value for a failing constraint test to a + MessageWriter. The default implementation simply writes + the raw value of actual, leaving it to the writer to + perform any formatting. + + The writer on which the actual value is displayed + + + + BinaryOperation is the abstract base of all constraints + that combine two other constraints in some fashion. + + + + + The first constraint being combined + + + + + The second constraint being combined + + + + + Construct a BinaryOperation from two other constraints + + The first constraint + The second constraint + + + + AndConstraint succeeds only if both members succeed. + + + + + Create an AndConstraint from two other constraints + + The first constraint + The second constraint + + + + Apply both member constraints to an actual value, succeeding + succeeding only if both of them succeed. + + The actual value + True if the constraints both succeeded + + + + Write a description for this contraint to a MessageWriter + + The MessageWriter to receive the description + + + + OrConstraint succeeds if either member succeeds + + + + + Create an OrConstraint from two other constraints + + The first constraint + The second constraint + + + + Apply the member constraints to an actual value, succeeding + succeeding as soon as one of them succeeds. + + The actual value + True if either constraint succeeded + + + + Write a description for this contraint to a MessageWriter + + The MessageWriter to receive the description + + + + The Numerics class contains common operations on numeric values. + + + + + Checks the type of the object, returning true if + the object is a numeric type. + + The object to check + true if the object is a numeric type + + + + Checks the type of the object, returning true if + the object is a floating point numeric type. + + The object to check + true if the object is a floating point numeric type + + + + Checks the type of the object, returning true if + the object is a fixed point numeric type. + + The object to check + true if the object is a fixed point numeric type + + + + The Is class is a helper class with properties and methods + that supply a number of constraints used in Asserts. + + + + + Is.Null returns a static constraint that tests for null + + + + + Is.True returns a static constraint that tests whether a value is true + + + + + Is.False returns a static constraint that tests whether a value is false + + + + + Is.NaN returns a static constraint that tests whether a value is an NaN + + + + + Is.Empty returns a static constraint that tests whether a string or collection is empty + + + + + Is.Unique returns a static constraint that tests whether a collection contains all unque items. + + + + + Is.EqualTo returns a constraint that tests whether the + actual value equals the supplied argument + + + + + + + Is.SameAs returns a constraint that tests whether the + actual value is the same object as the supplied argument. + + + + + + + Is.GreaterThan returns a constraint that tests whether the + actual value is greater than the suppled argument + + + + + Is.GreaterThanOrEqualTo returns a constraint that tests whether the + actual value is greater than or equal to the suppled argument + + + + + Is.AtLeast is a synonym for Is.GreaterThanOrEqualTo + + + + + Is.LessThan returns a constraint that tests whether the + actual value is less than the suppled argument + + + + + Is.LessThanOrEqualTo returns a constraint that tests whether the + actual value is less than or equal to the suppled argument + + + + + Is.AtMost is a synonym for Is.LessThanOrEqualTo + + + + + Is.TypeOf returns a constraint that tests whether the actual + value is of the exact type supplied as an argument. + + + + + Is.InstanceOfType returns a constraint that tests whether + the actual value is of the type supplied as an argument + or a derived type. + + + + + Is.AssignableFrom returns a constraint that tests whether + the actual value is assignable from the type supplied as + an argument. + + + + + + + Is.EquivalentTo returns a constraint that tests whether + the actual value is a collection containing the same + elements as the collection supplied as an arument + + + + + Is.SubsetOf returns a constraint that tests whether + the actual value is a subset of the collection + supplied as an arument + + + + + Is.Not returns a ConstraintBuilder that negates + the constraint that follows it. + + + + + Is.All returns a ConstraintBuilder, which will apply + the following constraint to all members of a collection, + succeeding if all of them succeed. This property is + a synonym for Has.AllItems. + + + + + The Iz class is a synonym for Is intended for use in VB, + which regards Is as a keyword. + + + + + The Text class is a helper class with properties and methods + that supply a number of constraints used with strings. + + + + + Contains returns a constraint that succeeds if the actual + value contains the substring supplied as an argument. + + + + + DoesNotContain returns a constraint that fails if the actual + value contains the substring supplied as an argument. + + + + + StartsWith returns a constraint that succeeds if the actual + value starts with the substring supplied as an argument. + + + + + DoesNotStartWith returns a constraint that fails if the actual + value starts with the substring supplied as an argument. + + + + + EndsWith returns a constraint that succeeds if the actual + value ends with the substring supplied as an argument. + + + + + DoesNotEndWith returns a constraint that fails if the actual + value ends with the substring supplied as an argument. + + + + + Matches returns a constraint that succeeds if the actual + value matches the pattern supplied as an argument. + + + + + + + DoesNotMatch returns a constraint that failss if the actual + value matches the pattern supplied as an argument. + + + + + + + Text.All returns a ConstraintBuilder, which will apply + the following constraint to all members of a collection, + succeeding if all of them succeed. + + + + + The List class is a helper class with properties and methods + that supply a number of constraints used with lists and collections. + + + + + List.Map returns a ListMapper, which can be used to map + the original collection to another collection. + + + + + + + ListMapper is used to transform a collection used as an actual argument + producing another collection to be used in the assertion. + + + + + Construct a ListMapper based on a collection + + The collection to be transformed + + + + Produces a collection containing all the values of a property + + The collection of property values + + + + + Summary description for HasNoPrefixB. + + + + + Returns a new ConstraintBuilder, which will apply the + following constraint to a named property of the object + being tested. + + The name of the property + + + + Returns a new PropertyConstraint checking for the + existence of a particular property value. + + The name of the property to look for + The expected value of the property + + + + Returns a new PropertyConstraint for the Length property + + + + + + + Returns a new PropertyConstraint or the Count property + + + + + + + Returns a new CollectionContainsConstraint checking for the + presence of a particular object in the collection. + + The expected object + + + + Has.No returns a ConstraintBuilder that negates + the constraint that follows it. + + + + + Has.AllItems returns a ConstraintBuilder, which will apply + the following constraint to all members of a collection, + succeeding if all of them succeed. + + + + + Has.Some returns a ConstraintBuilder, which will apply + the following constraint to all members of a collection, + succeeding if any of them succeed. It is a synonym + for Has.Item. + + + + + Has.None returns a ConstraintBuilder, which will apply + the following constraint to all members of a collection, + succeeding only if none of them succeed. + + + + + Nested class that allows us to restrict the number + of key words that may appear after Has.No. + + + + + Return a ConstraintBuilder conditioned to apply + the following constraint to a property. + + The property name + A ConstraintBuilder + + + + Return a Constraint that succeeds if the expected object is + not contained in a collection. + + The expected object + A Constraint + + + + The Assert class contains a collection of static methods that + implement the most common assertions used in NUnit. + + + + + We don't actually want any instances of this object, but some people + like to inherit from it to add other static methods. Hence, the + protected constructor disallows any instances of this object. + + + + + The Equals method throws an AssertionException. This is done + to make sure there is no mistake by calling this function. + + + + + + + override the default ReferenceEquals to throw an AssertionException. This + implementation makes sure there is no mistake in calling this function + as part of Assert. + + + + + + + Asserts that a condition is true. If the condition is false the method throws + an . + + The evaluated condition + The message to display if the condition is false + Arguments to be used in formatting the message + + + + Asserts that a condition is true. If the condition is false the method throws + an . + + The evaluated condition + The message to display if the condition is false + + + + Asserts that a condition is true. If the condition is false the method throws + an . + + The evaluated condition + + + + Asserts that a condition is false. If the condition is true the method throws + an . + + The evaluated condition + The message to display if the condition is true + Arguments to be used in formatting the message + + + + Asserts that a condition is false. If the condition is true the method throws + an . + + The evaluated condition + The message to display if the condition is true + + + + Asserts that a condition is false. If the condition is true the method throws + an . + + The evaluated condition + + + + Verifies that the object that is passed in is not equal to null + If the object is null then an + is thrown. + + The object that is to be tested + The message to be displayed when the object is null + Arguments to be used in formatting the message + + + + Verifies that the object that is passed in is not equal to null + If the object is null then an + is thrown. + + The object that is to be tested + The message to be displayed when the object is null + + + + Verifies that the object that is passed in is not equal to null + If the object is null then an + is thrown. + + The object that is to be tested + + + + Verifies that the object that is passed in is equal to null + If the object is not null then an + is thrown. + + The object that is to be tested + The message to be displayed when the object is not null + Arguments to be used in formatting the message + + + + Verifies that the object that is passed in is equal to null + If the object is not null then an + is thrown. + + The object that is to be tested + The message to be displayed when the object is not null + + + + Verifies that the object that is passed in is equal to null + If the object is not null null then an + is thrown. + + The object that is to be tested + + + + Verifies that the double is passed is an NaN value. + If the object is not NaN then an + is thrown. + + The value that is to be tested + The message to be displayed when the object is not null + Arguments to be used in formatting the message + + + + Verifies that the double is passed is an NaN value. + If the object is not NaN then an + is thrown. + + The object that is to be tested + The message to be displayed when the object is not null + + + + Verifies that the double is passed is an NaN value. + If the object is not NaN then an + is thrown. + + The object that is to be tested + + + + Assert that a string is empty - that is equal to string.Empty + + The string to be tested + The message to be displayed on failure + Arguments to be used in formatting the message + + + + Assert that a string is empty - that is equal to string.Emtpy + + The string to be tested + The message to be displayed on failure + + + + Assert that a string is empty - that is equal to string.Emtpy + + The string to be tested + + + + Assert that an array, list or other collection is empty + + An array, list or other collection implementing ICollection + The message to be displayed on failure + Arguments to be used in formatting the message + + + + Assert that an array, list or other collection is empty + + An array, list or other collection implementing ICollection + The message to be displayed on failure + + + + Assert that an array,list or other collection is empty + + An array, list or other collection implementing ICollection + + + + Assert that a string is not empty - that is not equal to string.Empty + + The string to be tested + The message to be displayed on failure + Arguments to be used in formatting the message + + + + Assert that a string is empty - that is equal to string.Emtpy + + The string to be tested + The message to be displayed on failure + + + + Assert that a string is empty - that is equal to string.Emtpy + + The string to be tested + + + + Assert that an array, list or other collection is empty + + An array, list or other collection implementing ICollection + The message to be displayed on failure + Arguments to be used in formatting the message + + + + Assert that an array, list or other collection is empty + + An array, list or other collection implementing ICollection + The message to be displayed on failure + + + + Assert that an array,list or other collection is empty + + An array, list or other collection implementing ICollection + + + + Asserts that an object may be assigned a value of a given Type. + + The expected Type. + The object under examination + + + + Asserts that an object may be assigned a value of a given Type. + + The expected Type. + The object under examination + The messge to display in case of failure + + + + Asserts that an object may be assigned a value of a given Type. + + The expected Type. + The object under examination + The message to display in case of failure + Array of objects to be used in formatting the message + + + + Asserts that an object may not be assigned a value of a given Type. + + The expected Type. + The object under examination + + + + Asserts that an object may not be assigned a value of a given Type. + + The expected Type. + The object under examination + The messge to display in case of failure + + + + Asserts that an object may not be assigned a value of a given Type. + + The expected Type. + The object under examination + The message to display in case of failure + Array of objects to be used in formatting the message + + + + Asserts that an object is an instance of a given type. + + The expected Type + The object being examined + + + + Asserts that an object is an instance of a given type. + + The expected Type + The object being examined + A message to display in case of failure + + + + Asserts that an object is an instance of a given type. + + The expected Type + The object being examined + A message to display in case of failure + An array of objects to be used in formatting the message + + + + Asserts that an object is not an instance of a given type. + + The expected Type + The object being examined + + + + Asserts that an object is not an instance of a given type. + + The expected Type + The object being examined + A message to display in case of failure + + + + Asserts that an object is not an instance of a given type. + + The expected Type + The object being examined + A message to display in case of failure + An array of objects to be used in formatting the message + + + + Verifies that two ints are equal. If they are not, then an + is thrown. + + The expected value + The actual value + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that two ints are equal. If they are not, then an + is thrown. + + The expected value + The actual value + The message that will be displayed on failure + + + + Verifies that two ints are equal. If they are not, then an + is thrown. + + The expected value + The actual value + + + + Verifies that two longs are equal. If they are not, then an + is thrown. + + The expected value + The actual value + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that two longs are equal. If they are not, then an + is thrown. + + The expected value + The actual value + The message that will be displayed on failure + + + + Verifies that two longs are equal. If they are not, then an + is thrown. + + The expected value + The actual value + + + + Verifies that two uints are equal. If they are not, then an + is thrown. + + The expected value + The actual value + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that two uints are equal. If they are not, then an + is thrown. + + The expected value + The actual value + The message that will be displayed on failure + + + + Verifies that two uints are equal. If they are not, then an + is thrown. + + The expected value + The actual value + + + + Verifies that two ulongs are equal. If they are not, then an + is thrown. + + The expected value + The actual value + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that two ulongs are equal. If they are not, then an + is thrown. + + The expected value + The actual value + The message that will be displayed on failure + + + + Verifies that two ulongs are equal. If they are not, then an + is thrown. + + The expected value + The actual value + + + + Verifies that two decimals are equal. If they are not, then an + is thrown. + + The expected value + The actual value + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that two decimal are equal. If they are not, then an + is thrown. + + The expected value + The actual value + The message that will be displayed on failure + + + + Verifies that two decimals are equal. If they are not, then an + is thrown. + + The expected value + The actual value + + + + Verifies that two doubles are equal considering a delta. If the + expected value is infinity then the delta value is ignored. If + they are not equals then an is + thrown. + + The expected value + The actual value + The maximum acceptable difference between the + the expected and the actual + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that two doubles are equal considering a delta. If the + expected value is infinity then the delta value is ignored. If + they are not equals then an is + thrown. + + The expected value + The actual value + The maximum acceptable difference between the + the expected and the actual + The message that will be displayed on failure + + + + Verifies that two doubles are equal considering a delta. If the + expected value is infinity then the delta value is ignored. If + they are not equals then an is + thrown. + + The expected value + The actual value + The maximum acceptable difference between the + the expected and the actual + + + + Verifies that two floats are equal considering a delta. If the + expected value is infinity then the delta value is ignored. If + they are not equals then an is + thrown. + + The expected value + The actual value + The maximum acceptable difference between the + the expected and the actual + The message displayed upon failure + Arguments to be used in formatting the message + + + + Verifies that two floats are equal considering a delta. If the + expected value is infinity then the delta value is ignored. If + they are not equals then an is + thrown. + + The expected value + The actual value + The maximum acceptable difference between the + the expected and the actual + The message displayed upon failure + + + + Verifies that two floats are equal considering a delta. If the + expected value is infinity then the delta value is ignored. If + they are not equals then an is + thrown. + + The expected value + The actual value + The maximum acceptable difference between the + the expected and the actual + + + + Verifies that two objects are equal. Two objects are considered + equal if both are null, or if both have the same value. All + non-numeric types are compared by using the Equals method. + Arrays are compared by comparing each element using the same rules. + If they are not equal an is thrown. + + The value that is expected + The actual value + The message to display if objects are not equal + Arguments to be used in formatting the message + + + + Verifies that two objects are equal. Two objects are considered + equal if both are null, or if both have the same value. All + non-numeric types are compared by using the Equals method. + If they are not equal an is thrown. + + The value that is expected + The actual value + The message to display if objects are not equal + + + + Verifies that two objects are equal. Two objects are considered + equal if both are null, or if both have the same value. All + non-numeric types are compared by using the Equals method. + If they are not equal an is thrown. + + The value that is expected + The actual value + + + + Asserts that two objects are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the two objects are the same object. + Arguments to be used in formatting the message + + + + Asserts that two objects are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the objects are the same + + + + Asserts that two objects are not equal. If they are equal + an is thrown. + + The expected object + The actual object + + + + Asserts that two ints are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the two objects are the same object. + Arguments to be used in formatting the message + + + + Asserts that two ints are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the objects are the same + + + + Asserts that two ints are not equal. If they are equal + an is thrown. + + The expected object + The actual object + + + + Asserts that two longss are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the two objects are the same object. + Arguments to be used in formatting the message + + + + Asserts that two longs are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the objects are the same + + + + Asserts that two longs are not equal. If they are equal + an is thrown. + + The expected object + The actual object + + + + Asserts that two uints are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the two objects are the same object. + Arguments to be used in formatting the message + + + + Asserts that two uints are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the objects are the same + + + + Asserts that two uints are not equal. If they are equal + an is thrown. + + The expected object + The actual object + + + + Asserts that two ulongs are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the two objects are the same object. + Arguments to be used in formatting the message + + + + Asserts that two ulongs are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the objects are the same + + + + Asserts that two ulong are not equal. If they are equal + an is thrown. + + The expected object + The actual object + + + + Asserts that two decimals are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the two objects are the same object. + Arguments to be used in formatting the message + + + + Asserts that two decimals are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the objects are the same + + + + Asserts that two decimals are not equal. If they are equal + an is thrown. + + The expected object + The actual object + + + + Asserts that two floats are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the two objects are the same object. + Arguments to be used in formatting the message + + + + Asserts that two floats are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the objects are the same + + + + Asserts that two floats are not equal. If they are equal + an is thrown. + + The expected object + The actual object + + + + Asserts that two doubles are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the two objects are the same object. + Arguments to be used in formatting the message + + + + Asserts that two doubles are not equal. If they are equal + an is thrown. + + The expected object + The actual object + The message to be displayed when the objects are the same + + + + Asserts that two doubles are not equal. If they are equal + an is thrown. + + The expected object + The actual object + + + + Asserts that two objects refer to the same object. If they + are not the same an is thrown. + + The expected object + The actual object + The message to be displayed when the two objects are not the same object. + Arguments to be used in formatting the message + + + + Asserts that two objects refer to the same object. If they + are not the same an is thrown. + + The expected object + The actual object + The message to be displayed when the object is null + + + + Asserts that two objects refer to the same object. If they + are not the same an is thrown. + + The expected object + The actual object + + + + Asserts that two objects do not refer to the same object. If they + are the same an is thrown. + + The expected object + The actual object + The message to be displayed when the two objects are the same object. + Arguments to be used in formatting the message + + + + Asserts that two objects do not refer to the same object. If they + are the same an is thrown. + + The expected object + The actual object + The message to be displayed when the objects are the same + + + + Asserts that two objects do not refer to the same object. If they + are the same an is thrown. + + The expected object + The actual object + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Asserts that an object is contained in a list. + + The expected object + The list to be examined + The message to display in case of failure + Arguments used in formatting the message + + + + Asserts that an object is contained in a list. + + The expected object + The list to be examined + The message to display in case of failure + + + + Asserts that an object is contained in a list. + + The expected object + The list to be examined + + + + Throws an with the message and arguments + that are passed in. This is used by the other Assert functions. + + The message to initialize the with. + Arguments to be used in formatting the message + + + + Throws an with the message that is + passed in. This is used by the other Assert functions. + + The message to initialize the with. + + + + Throws an . + This is used by the other Assert functions. + + + + + Throws an with the message and arguments + that are passed in. This causes the test to be reported as ignored. + + The message to initialize the with. + Arguments to be used in formatting the message + + + + Throws an with the message that is + passed in. This causes the test to be reported as ignored. + + The message to initialize the with. + + + + Throws an . + This causes the test to be reported as ignored. + + + + + NOTE: The use of asserters for extending NUnit has + now been replaced by the use of constraints. This + method is marked obsolete. + + Test the condition asserted by an asserter and throw + an assertion exception using provided message on failure. + + An object that implements IAsserter + + + + Apply a constraint to an actual value, succeeding if the constraint + is satisfied and throwing an assertion exception on failure. + + A Constraint to be applied + The actual value to test + + + + Apply a constraint to an actual value, succeedingt if the constraint + is satisfied and throwing an assertion exception on failure. + + A Constraint to be applied + The actual value to test + The message that will be displayed on failure + + + + Apply a constraint to an actual value, succeedingt if the constraint + is satisfied and throwing an assertion exception on failure. + + A Constraint to be applied + The actual value to test + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that a condition is true. If the condition is false the method throws + an . + + The evaluated condition + The message to display if the condition is false + Arguments to be used in formatting the message + + + + Asserts that a condition is true. If the condition is false the method throws + an . + + The evaluated condition + The message to display if the condition is false + + + + Asserts that a condition is true. If the condition is false the method throws + an . + + The evaluated condition + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater or equal to than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater or equal to than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater or equal to than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than or equal to the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + The message that will be displayed on failure + + + + Verifies that the first value is greater than the second + value. If they are not, then an + is thrown. + + The first value, expected to be greater + The second value, expected to be less + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + The message that will be displayed on failure + + + + Verifies that the first value is less than or equal to the second + value. If it is not, then an + is thrown. + + The first value, expected to be less + The second value, expected to be greater + + + + Gets the number of assertions executed so far and + resets the counter to zero. + + + + + Enumeration indicating how the expected message parameter is to be used + + + + Expect an exact match + + + Expect a message containing the parameter string + + + Match the regular expression provided as a parameter + + + + ExpectedExceptionAttribute + + + + + + Constructor for a non-specific exception + + + + + Constructor for a given type of exception + + The type of the expected exception + + + + Constructor for a given exception name + + The full name of the expected exception + + + + Constructor for a given type of exception and expected message text + + The type of the expected exception + The expected message text + + + + Constructor for a given exception name and expected message text + + The full name of the expected exception + The expected messge text + + + + Gets or sets the expected exception type + + + + + Gets or sets the full Type name of the expected exception + + + + + Gets or sets the expected message text + + + + + Gets or sets the user message displayed in case of failure + + + + + Gets or sets the type of match to be performed on the expected message + + + + + Gets the name of a method to be used as an exception handler + + + + + A set of Assert methods operationg on one or more collections + + + + + The Equals method throws an AssertionException. This is done + to make sure there is no mistake by calling this function. + + + + + + + override the default ReferenceEquals to throw an AssertionException. This + implementation makes sure there is no mistake in calling this function + as part of Assert. + + + + + + + Asserts that all items contained in collection are of the type specified by expectedType. + + ICollection of objects to be considered + System.Type that all objects in collection must be instances of + + + + Asserts that all items contained in collection are of the type specified by expectedType. + + ICollection of objects to be considered + System.Type that all objects in collection must be instances of + The message that will be displayed on failure + + + + Asserts that all items contained in collection are of the type specified by expectedType. + + ICollection of objects to be considered + System.Type that all objects in collection must be instances of + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that all items contained in collection are not equal to null. + + ICollection of objects to be considered + + + + Asserts that all items contained in collection are not equal to null. + + ICollection of objects to be considered + The message that will be displayed on failure + + + + Asserts that all items contained in collection are not equal to null. + + ICollection of objects to be considered + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Ensures that every object contained in collection exists within the collection + once and only once. + + ICollection of objects to be considered + + + + Ensures that every object contained in collection exists within the collection + once and only once. + + ICollection of objects to be considered + The message that will be displayed on failure + + + + Ensures that every object contained in collection exists within the collection + once and only once. + + ICollection of objects to be considered + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that expected and actual are exactly equal. The collections must have the same count, + and contain the exact same objects in the same order. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + + + + Asserts that expected and actual are exactly equal. The collections must have the same count, + and contain the exact same objects in the same order. + If comparer is not null then it will be used to compare the objects. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The IComparer to use in comparing objects from each ICollection + + + + Asserts that expected and actual are exactly equal. The collections must have the same count, + and contain the exact same objects in the same order. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The message that will be displayed on failure + + + + Asserts that expected and actual are exactly equal. The collections must have the same count, + and contain the exact same objects in the same order. + If comparer is not null then it will be used to compare the objects. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The IComparer to use in comparing objects from each ICollection + The message that will be displayed on failure + + + + Asserts that expected and actual are exactly equal. The collections must have the same count, + and contain the exact same objects in the same order. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that expected and actual are exactly equal. The collections must have the same count, + and contain the exact same objects in the same order. + If comparer is not null then it will be used to compare the objects. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The IComparer to use in comparing objects from each ICollection + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that expected and actual are equivalent, containing the same objects but the match may be in any order. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + + + + Asserts that expected and actual are equivalent, containing the same objects but the match may be in any order. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The message that will be displayed on failure + + + + Asserts that expected and actual are equivalent, containing the same objects but the match may be in any order. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that expected and actual are not exactly equal. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + + + + Asserts that expected and actual are not exactly equal. + If comparer is not null then it will be used to compare the objects. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The IComparer to use in comparing objects from each ICollection + + + + Asserts that expected and actual are not exactly equal. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The message that will be displayed on failure + + + + Asserts that expected and actual are not exactly equal. + If comparer is not null then it will be used to compare the objects. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The IComparer to use in comparing objects from each ICollection + The message that will be displayed on failure + + + + Asserts that expected and actual are not exactly equal. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that expected and actual are not exactly equal. + If comparer is not null then it will be used to compare the objects. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The IComparer to use in comparing objects from each ICollection + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that expected and actual are not equivalent. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + + + + Asserts that expected and actual are not equivalent. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The message that will be displayed on failure + + + + Asserts that expected and actual are not equivalent. + + The first ICollection of objects to be considered + The second ICollection of objects to be considered + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that collection contains actual as an item. + + ICollection of objects to be considered + Object to be found within collection + + + + Asserts that collection contains actual as an item. + + ICollection of objects to be considered + Object to be found within collection + The message that will be displayed on failure + + + + Asserts that collection contains actual as an item. + + ICollection of objects to be considered + Object to be found within collection + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that collection does not contain actual as an item. + + ICollection of objects to be considered + Object that cannot exist within collection + + + + Asserts that collection does not contain actual as an item. + + ICollection of objects to be considered + Object that cannot exist within collection + The message that will be displayed on failure + + + + Asserts that collection does not contain actual as an item. + + ICollection of objects to be considered + Object that cannot exist within collection + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that superset is not a subject of subset. + + The ICollection superset to be considered + The ICollection subset to be considered + + + + Asserts that superset is not a subject of subset. + + The ICollection superset to be considered + The ICollection subset to be considered + The message that will be displayed on failure + + + + Asserts that superset is not a subject of subset. + + The ICollection superset to be considered + The ICollection subset to be considered + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that superset is a subset of subset. + + The ICollection superset to be considered + The ICollection subset to be considered + + + + Asserts that superset is a subset of subset. + + The ICollection superset to be considered + The ICollection subset to be considered + The message that will be displayed on failure + + + + Asserts that superset is a subset of subset. + + The ICollection superset to be considered + The ICollection subset to be considered + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Assert that an array, list or other collection is empty + + An array, list or other collection implementing ICollection + The message to be displayed on failure + Arguments to be used in formatting the message + + + + Assert that an array, list or other collection is empty + + An array, list or other collection implementing ICollection + The message to be displayed on failure + + + + Assert that an array,list or other collection is empty + + An array, list or other collection implementing ICollection + + + + Assert that an array, list or other collection is empty + + An array, list or other collection implementing ICollection + The message to be displayed on failure + Arguments to be used in formatting the message + + + + Assert that an array, list or other collection is empty + + An array, list or other collection implementing ICollection + The message to be displayed on failure + + + + Assert that an array,list or other collection is empty + + An array, list or other collection implementing ICollection + + + + NOTE: The use of asserters for extending NUnit has + now been replaced by the use of constraints. This + class is marked obsolete. + + AbstractAsserter is the base class for all asserters. + Asserters encapsulate a condition test and generation + of an AssertionException with a tailored message. They + are used by the Assert class as helper objects. + + User-defined asserters may be passed to the + Assert.DoAssert method in order to implement + extended asserts. + + + + + NOTE: The use of asserters for extending NUnit has + now been replaced by the use of constraints. This + interface is marked obsolete. + + The interface implemented by an asserter. Asserters + encapsulate a condition test and generation of an + AssertionException with a tailored message. They + are used by the Assert class as helper objects. + + User-defined asserters may be passed to the + Assert.DoAssert method in order to implement + extended asserts. + + + + + Test the condition for the assertion. + + True if the test succeeds + + + + Return the message giving the failure reason. + The return value is unspecified if no failure + has occured. + + + + + The user-defined message for this asserter. + + + + + Arguments to use in formatting the user-defined message. + + + + + Our failure message object, initialized as needed + + + + + Constructs an AbstractAsserter + + The message issued upon failure + Arguments to be used in formatting the message + + + + Test method to be implemented by derived types. + Default always succeeds. + + True if the test succeeds + + + + AssertionFailureMessage object used internally + + + + + Message related to a failure. If no failure has + occured, the result is unspecified. + + + + + The Assertion class is obsolete and has been + replaced by the Assert class. + + + + + Asserts that a condition is true. If it isn't it throws + an . + + The message to display is the condition + is false + The evaluated condition + + + + Asserts that a condition is true. If it isn't it throws + an . + + The evaluated condition + + + + /// Asserts that two doubles are equal concerning a delta. If the + expected value is infinity then the delta value is ignored. + + The expected value + The actual value + The maximum acceptable difference between the + the expected and the actual + + + + /// Asserts that two singles are equal concerning a delta. If the + expected value is infinity then the delta value is ignored. + + The expected value + The actual value + The maximum acceptable difference between the + the expected and the actual + + + Asserts that two objects are equal. If they are not + an is thrown. + + + Asserts that two ints are equal. If they are not + an is thrown. + + + Asserts that two ints are equal. If they are not + an is thrown. + + + Asserts that two doubles are equal concerning a delta. + If the expected value is infinity then the delta value is ignored. + + + + Asserts that two floats are equal concerning a delta. + If the expected value is infinity then the delta value is ignored. + + + + + Asserts that two objects are equal. Two objects are considered + equal if both are null, or if both have the same value. Numeric + types are compared via string comparision on their contents to + avoid problems comparing values between different types. All + non-numeric types are compared by using the Equals method. + If they are not equal an is thrown. + + + + Asserts that an object isn't null. + + + Asserts that an object isn't null. + + + Asserts that an object is null. + + + Asserts that an object is null. + + + Asserts that two objects refer to the same object. If they + are not the same an is thrown. + + + + Asserts that two objects refer to the same object. + If they are not an is thrown. + + + + Fails a test with no message. + + + Fails a test with the given message. + + + + Thrown when an assertion failed. + + + + + The error message that explains + the reason for the exception + + + The error message that explains + the reason for the exception + The exception that caused the + current exception + + + + Serialization Constructor + + + + + AssertionFailureMessage encapsulates a failure message + issued as a result of an Assert failure. + + + + + Number of characters before a highlighted position before + clipping will occur. Clipped text is replaced with an + elipsis "..." + + + + + Number of characters after a highlighted position before + clipping will occur. Clipped text is replaced with an + elipsis "..." + + + + + Prefix used to start an expected value line. + Must be same length as actualPrefix. + + + + + Prefix used to start an actual value line. + Must be same length as expectedPrefix. + + + + + Construct an AssertionFailureMessage with a message + and optional arguments. + + + + + + + Construct an empty AssertionFailureMessage + + + + + Add an expected value line to the message containing + the text provided as an argument. + + Text describing what was expected. + + + + Add an actual value line to the message containing + the text provided as an argument. + + Text describing the actual value. + + + + Add an expected value line to the message containing + a string representation of the object provided. + + An object representing the expected value + + + + Add an expected value line to the message containing a double + and the tolerance used in making the comparison. + + The expected value + The tolerance specified in the Assert + + + + Add an actual value line to the message containing + a string representation of the object provided. + + An object representing what was actually found + + + + Display two lines that communicate the expected value, and the actual value + + The expected value + The actual value found + + + + Display two lines that communicate the expected value, the actual value and + the tolerance used in comparing two doubles. + + The expected value + The actual value found + The tolerance specified in the Assert + + + + Draws a marker under the expected/actual strings that highlights + where in the string a mismatch occurred. + + The position of the mismatch + + + + Reports whether the string lengths are the same or different, and + what the string lengths are. + + The expected string + The actual string value + + + + Called to create additional message lines when two objects have been + found to be unequal. If the inputs are strings, a special message is + rendered that can help track down where the strings are different, + based on differences in length, or differences in content. + + If the inputs are not strings, the ToString method of the objects + is used to show what is different about them. + + The expected value + The actual value + True if a case-insensitive comparison is being performed + + + + Called to create additional message lines when two doubles have been + found to be unequal, within the specified tolerance. + + + + + Constructs a message that can be displayed when the content of two + strings are different, but the string lengths are the same. The + message will clip the strings to a reasonable length, centered + around the first position where they are mismatched, and draw + a line marking the position of the difference to make comparison + quicker. + + The expected string value + The actual string value + True if a case-insensitive comparison is being performed + + + + Display a standard message showing the differences found between + two arrays that were expected to be equal. + + The expected array value + The actual array value + The index at which a difference was found + + + + Display a standard message showing the differences found between + two collections that were expected to be equal. + + The expected collection value + The actual collection value + The index at which a difference was found + + + + Get an array of indices representing the point in a collection or + array corresponding to a single int index into the collection. + + The collection to which the indices apply + Index in the collection + Array of indices + + + + Displays elements from a list on a line + + Text to prefix the line with + The list of items to display + The index in the list of the first element to display + The maximum number of elements to display + + + + Formats an object for display in a message line + + The object to be displayed + + + + + Tests two objects to determine if they are strings. + + + + + + + + Renders up to M characters before, and up to N characters after + the specified index position. If leading or trailing text is + clipped, and elipses "..." is added where the missing text would + be. + + Clips strings to limit previous or post newline characters, + since these mess up the comparison + + + + + + + + Shows the position two strings start to differ. Comparison + starts at the start index. + + + + + -1 if no mismatch found, or the index where mismatch found + + + + Turns CR, LF, or TAB into visual indicator to preserve visual marker + position. This is done by replacing the '\r' into '\\' and 'r' + characters, and the '\n' into '\\' and 'n' characters, and '\t' into + '\\' and 't' characters. + + Thus the single character becomes two characters for display. + + + + + + + Attribute used to apply a category to a test + + + + + The name of the category + + + + + Construct attribute for a given category + + The name of the category + + + + Protected constructor uses the Type name as the name + of the category. + + + + + The name of the category + + + + + Abstract base for Attributes that are used to include tests + in the test run based on environmental settings. + + + + + Constructor with no included items specified, for use + with named property syntax. + + + + + Constructor taking one or more included items + + Comma-delimited list of included items + + + + Name of the item that is needed in order for + a test to run. Multiple itemss may be given, + separated by a comma. + + + + + Name of the item to be excluded. Multiple items + may be given, separated by a comma. + + + + + The reason for including or excluding the test + + + + + PlatformAttribute is used to mark a test fixture or an + individual method as applying to a particular platform only. + + + + + Constructor with no platforms specified, for use + with named property syntax. + + + + + Constructor taking one or more platforms + + Comma-deliminted list of platforms + + + + CultureAttribute is used to mark a test fixture or an + individual method as applying to a particular Culture only. + + + + + Constructor with no cultures specified, for use + with named property syntax. + + + + + Constructor taking one or more cultures + + Comma-deliminted list of cultures + + + + MessageWriter is the abstract base for classes that write + constraint descriptions and messages in some form. The + class has separate methods for writing various components + of a message, allowing implementations to tailor the + presentation as needed. + + + + + Construct a MessageWriter given a culture + + + + + Method to write single line message with optional args, usually + written to precede the general failure message. + + The message to be written + Any arguments used in formatting the message + + + + Method to write single line message with optional args, usually + written to precede the general failure message, at a givel + indentation level. + + The indentation level of the message + The message to be written + Any arguments used in formatting the message + + + + Display Expected and Actual lines for a constraint. This + is called by MessageWriter's default implementation of + WriteMessageTo and provides the generic two-line display. + + The constraint that failed + + + + Display Expected and Actual lines for given values. This + method may be called by constraints that need more control over + the display of actual and expected values than is provided + by the default implementation. + + The expected value + The actual value causing the failure + + + + Display Expected and Actual lines for given values, including + a tolerance value on the Expected line. + + The expected value + The actual value causing the failure + The tolerance within which the test was made + + + + Display the expected and actual string values on separate lines. + If the mismatch parameter is >=0, an additional line is displayed + line containing a caret that points to the mismatch point. + + The expected string value + The actual string value + The point at which the strings don't match or -1 + If true, case is ignored in locating the point where the strings differ + + + + Writes the text for a connector. + + The connector. + + + + Writes the text for a predicate. + + The predicate. + + + + Writes the text for an expected value. + + The expected value. + + + + Writes the text for a modifier + + The modifier. + + + + Writes the text for an actual value. + + The actual value. + + + + Writes the text for a generalized value. + + The value. + + + + Writes the text for a collection value, + starting at a particular point, to a max length + + The collection containing elements to write. + The starting point of the elements to write + The maximum number of elements to write + + + + Abstract method to get the max line length + + + + + Summary description for SetCultureAttribute. + + + + + PropertyAttribute is used to attach information to a test as a name/value pair.. + + + + + The property name + + + + + The property value + + + + + Construct a PropertyAttribute with a name and value + + The name of the property + The property value + + + + Constructor for use by inherited classes that use the + name of the type as the property name. + + + + + Gets the property name + + + + + Gets the property value + + + + + Construct given the name of a culture + + + + + + TextMessageWriter writes constraint descriptions and messages + in displayable form as a text stream. It tailors the display + of individual message components to form the standard message + format of NUnit assertion failure messages. + + + + + Prefix used for the expected value line of a message + + + + + Prefix used for the actual value line of a message + + + + + Length of a message prefix + + + + + Construct a TextMessageWriter + + + + + Construct a TextMessageWriter, specifying a user message + and optional formatting arguments. + + + + + + + Method to write single line message with optional args, usually + written to precede the general failure message, at a givel + indentation level. + + The indentation level of the message + The message to be written + Any arguments used in formatting the message + + + + Display Expected and Actual lines for a constraint. This + is called by MessageWriter's default implementation of + WriteMessageTo and provides the generic two-line display. + + The constraint that failed + + + + Display Expected and Actual lines for given values. This + method may be called by constraints that need more control over + the display of actual and expected values than is provided + by the default implementation. + + The expected value + The actual value causing the failure + + + + Display Expected and Actual lines for given values, including + a tolerance value on the expected line. + + The expected value + The actual value causing the failure + The tolerance within which the test was made + + + + Display the expected and actual string values on separate lines. + If the mismatch parameter is >=0, an additional line is displayed + line containing a caret that points to the mismatch point. + + The expected string value + The actual string value + The point at which the strings don't match or -1 + If true, case is ignored in string comparisons + + + + Writes the text for a connector. + + The connector. + + + + Writes the text for a predicate. + + The predicate. + + + + Write the text for a modifier. + + The modifier. + + + + Writes the text for an expected value. + + The expected value. + + + + Writes the text for an actual value. + + The actual value. + + + + Writes the text for a generalized value. + + The value. + + + + Writes the text for a collection value, + starting at a particular point, to a max length + + The collection containing elements to write. + The starting point of the elements to write + The maximum number of elements to write + + + + Write the generic 'Expected' line for a constraint + + The constraint that failed + + + + Write the generic 'Expected' line for a given value + + The expected value + + + + Write the generic 'Expected' line for a given value + and tolerance. + + The expected value + The tolerance within which the test was made + + + + Write the generic 'Actual' line for a constraint + + The constraint for which the actual value is to be written + + + + Write the generic 'Actual' line for a given value + + The actual value causing a failure + + + + Gets the maximum line length for this writer + + + + + Basic Asserts on strings. + + + + + The Equals method throws an AssertionException. This is done + to make sure there is no mistake by calling this function. + + + + + + + override the default ReferenceEquals to throw an AssertionException. This + implementation makes sure there is no mistake in calling this function + as part of Assert. + + + + + + + Asserts that a string is found within another string. + + The expected string + The string to be examined + The message to display in case of failure + Arguments used in formatting the message + + + + Asserts that a string is found within another string. + + The expected string + The string to be examined + The message to display in case of failure + + + + Asserts that a string is found within another string. + + The expected string + The string to be examined + + + + Asserts that a string starts with another string. + + The expected string + The string to be examined + The message to display in case of failure + Arguments used in formatting the message + + + + Asserts that a string starts with another string. + + The expected string + The string to be examined + The message to display in case of failure + + + + Asserts that a string starts with another string. + + The expected string + The string to be examined + + + + Asserts that a string ends with another string. + + The expected string + The string to be examined + The message to display in case of failure + Arguments used in formatting the message + + + + Asserts that a string ends with another string. + + The expected string + The string to be examined + The message to display in case of failure + + + + Asserts that a string ends with another string. + + The expected string + The string to be examined + + + + Asserts that two strings are equal, without regard to case. + + The expected string + The actual string + The message to display in case of failure + Arguments used in formatting the message + + + + Asserts that two strings are equal, without regard to case. + + The expected string + The actual string + The message to display in case of failure + + + + Asserts that two strings are equal, without regard to case. + + The expected string + The actual string + + + + Asserts that a string matches an expected regular expression pattern. + + The expected expression + The actual string + The message to display in case of failure + Arguments used in formatting the message + + + + Asserts that a string matches an expected regular expression pattern. + + The expected expression + The actual string + The message to display in case of failure + + + + Asserts that a string matches an expected regular expression pattern. + + The expected expression + The actual string + + + + Static methods used in creating messages + + + + + Returns the representation of a type as used in NUnitLite. + This is the same as Type.ToString() except for arrays, + which are displayed with their declared sizes. + + + + + + + Converts any control characters in a string + to their escaped representation. + + The string to be converted + The converted string + + + + Return the a string representation for a set of indices into an array + + Array of indices for which a string is needed + + + + Get an array of indices representing the point in a collection or + array corresponding to a single int index into the collection. + + The collection to which the indices apply + Index in the collection + Array of indices + + + + Clip a string around a particular point, returning the clipped + string with ellipses representing the removed parts + + The string to be clipped + The maximum permitted length of the result string + The point around which clipping is to occur + The clipped string + + + + Shows the position two strings start to differ. Comparison + starts at the start index. + + The expected string + The actual string + The index in the strings at which comparison should start + Boolean indicating whether case should be ignored + -1 if no mismatch found, or the index where mismatch found + + + + AssertionHelper is an optional base class for user tests, + allowing the use of shorter names for constraints and + asserts and avoiding conflict with the definition of + , from which it inherits much of its + behavior, in certain mock object frameworks. + + + + + Apply a constraint to an actual value, succeeding if the constraint + is satisfied and throwing an assertion exception on failure. Works + identically to + + A Constraint to be applied + The actual value to test + + + + Apply a constraint to an actual value, succeeding if the constraint + is satisfied and throwing an assertion exception on failure. Works + identically to + + A Constraint to be applied + The actual value to test + The message that will be displayed on failure + + + + Apply a constraint to an actual value, succeeding if the constraint + is satisfied and throwing an assertion exception on failure. Works + identically to + + A Constraint to be applied + The actual value to test + The message that will be displayed on failure + Arguments to be used in formatting the message + + + + Asserts that a condition is true. If the condition is false the method throws + an . Works Identically to + . + + The evaluated condition + The message to display if the condition is false + Arguments to be used in formatting the message + + + + Asserts that a condition is true. If the condition is false the method throws + an . Works Identically to + . + + The evaluated condition + The message to display if the condition is false + + + + Asserts that a condition is true. If the condition is false the method throws + an . Works Identically to . + + The evaluated condition + + + + Returns a ListMapper based on a collection. + + The original collection + + + + + Summary description for FileAssert. + + + + + The Equals method throws an AssertionException. This is done + to make sure there is no mistake by calling this function. + + + + + + + override the default ReferenceEquals to throw an AssertionException. This + implementation makes sure there is no mistake in calling this function + as part of Assert. + + + + + + + We don't actually want any instances of this object, but some people + like to inherit from it to add other static methods. Hence, the + protected constructor disallows any instances of this object. + + + + + Verifies that two Streams are equal. Two Streams are considered + equal if both are null, or if both have the same value byte for byte. + If they are not equal an is thrown. + + The expected Stream + The actual Stream + The message to display if Streams are not equal + Arguments to be used in formatting the message + + + + Verifies that two Streams are equal. Two Streams are considered + equal if both are null, or if both have the same value byte for byte. + If they are not equal an is thrown. + + The expected Stream + The actual Stream + The message to display if objects are not equal + + + + Verifies that two Streams are equal. Two Streams are considered + equal if both are null, or if both have the same value byte for byte. + If they are not equal an is thrown. + + The expected Stream + The actual Stream + + + + Verifies that two files are equal. Two files are considered + equal if both are null, or if both have the same value byte for byte. + If they are not equal an is thrown. + + A file containing the value that is expected + A file containing the actual value + The message to display if Streams are not equal + Arguments to be used in formatting the message + + + + Verifies that two files are equal. Two files are considered + equal if both are null, or if both have the same value byte for byte. + If they are not equal an is thrown. + + A file containing the value that is expected + A file containing the actual value + The message to display if objects are not equal + + + + Verifies that two files are equal. Two files are considered + equal if both are null, or if both have the same value byte for byte. + If they are not equal an is thrown. + + A file containing the value that is expected + A file containing the actual value + + + + Verifies that two files are equal. Two files are considered + equal if both are null, or if both have the same value byte for byte. + If they are not equal an is thrown. + + The path to a file containing the value that is expected + The path to a file containing the actual value + The message to display if Streams are not equal + Arguments to be used in formatting the message + + + + Verifies that two files are equal. Two files are considered + equal if both are null, or if both have the same value byte for byte. + If they are not equal an is thrown. + + The path to a file containing the value that is expected + The path to a file containing the actual value + The message to display if objects are not equal + + + + Verifies that two files are equal. Two files are considered + equal if both are null, or if both have the same value byte for byte. + If they are not equal an is thrown. + + The path to a file containing the value that is expected + The path to a file containing the actual value + + + + Asserts that two Streams are not equal. If they are equal + an is thrown. + + The expected Stream + The actual Stream + The message to be displayed when the two Stream are the same. + Arguments to be used in formatting the message + + + + Asserts that two Streams are not equal. If they are equal + an is thrown. + + The expected Stream + The actual Stream + The message to be displayed when the Streams are the same. + + + + Asserts that two Streams are not equal. If they are equal + an is thrown. + + The expected Stream + The actual Stream + + + + Asserts that two files are not equal. If they are equal + an is thrown. + + A file containing the value that is expected + A file containing the actual value + The message to display if Streams are not equal + Arguments to be used in formatting the message + + + + Asserts that two files are not equal. If they are equal + an is thrown. + + A file containing the value that is expected + A file containing the actual value + The message to display if objects are not equal + + + + Asserts that two files are not equal. If they are equal + an is thrown. + + A file containing the value that is expected + A file containing the actual value + + + + Asserts that two files are not equal. If they are equal + an is thrown. + + The path to a file containing the value that is expected + The path to a file containing the actual value + The message to display if Streams are not equal + Arguments to be used in formatting the message + + + + Asserts that two files are not equal. If they are equal + an is thrown. + + The path to a file containing the value that is expected + The path to a file containing the actual value + The message to display if objects are not equal + + + + Asserts that two files are not equal. If they are equal + an is thrown. + + The path to a file containing the value that is expected + The path to a file containing the actual value + + + + Thrown when an assertion failed. + + + + + + + The error message that explains + the reason for the exception + The exception that caused the + current exception + + + + Serialization Constructor + + + + + Obsolete class, formerly used to identify tests through + inheritance. Avoid using this class for new tests. + + + + + Method called immediately before running the test. + + + + + Method Called immediately after running the test. It is + guaranteed to be called, even if an exception is thrown. + + + + + Attribute used to mark a class that contains one-time SetUp + and/or TearDown methods that apply to all the tests in a + namespace or an assembly. + + + + + SetUpFixtureAttribute is used to identify a SetUpFixture + + + + + Attribute used to mark a static (shared in VB) property + that returns a list of tests. + + + + + Attribute used to identify a method that is called + immediately after each test is run. The method is + guaranteed to be called, even if an exception is thrown. + + + + + Adding this attribute to a method within a + class makes the method callable from the NUnit test runner. There is a property + called Description which is optional which you can provide a more detailed test + description. This class cannot be inherited. + + + + [TestFixture] + public class Fixture + { + [Test] + public void MethodToTest() + {} + + [Test(Description = "more detailed description")] + publc void TestDescriptionMethod() + {} + } + + + + + + Descriptive text for this test + + + + + [TestFixture] + public class ExampleClass + {} + + + + + Descriptive text for this fixture + + + + + Attribute used to identify a method that is + called before any tests in a fixture are run. + + + + + Attribute used to identify a method that is called after + all the tests in a fixture have run. The method is + guaranteed to be called, even if an exception is thrown. + + + + + Attribute used to mark a test that is to be ignored. + Ignored tests result in a warning message when the + tests are run. + + + + + Constructs the attribute without giving a reason + for ignoring the test. + + + + + Constructs the attribute giving a reason for ignoring the test + + The reason for ignoring the test + + + + The reason for ignoring a test + + + + + ExplicitAttribute marks a test or test fixture so that it will + only be run if explicitly executed from the gui or command line + or if it is included by use of a filter. The test will not be + run simply because an enclosing suite is run. + + + + + Default constructor + + + + + Constructor with a reason + + The reason test is marked explicit + + + + The reason test is marked explicit + + + + + Attribute used to provide descriptive text about a + test case or fixture. + + + + + Construct the attribute + + Text describing the test + + + + Gets the test description + + + + + Interface implemented by a user fixture in order to + validate any expected exceptions. It is only called + for test methods marked with the ExpectedException + attribute. + + + + + Method to handle an expected exception + + The exception to be handled + + + diff --git a/Src/Newtonsoft.Json.Tests/AspNetAjaxDateTimeConverterTest.cs b/Src/Newtonsoft.Json.Tests/AspNetAjaxDateTimeConverterTest.cs new file mode 100644 index 00000000..f76ded52 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/AspNetAjaxDateTimeConverterTest.cs @@ -0,0 +1,70 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json; +using System.IO; +using Newtonsoft.Json.Converters; + +namespace Newtonsoft.Json.Tests +{ + [TestFixture] + public class AspNetAjaxDateTimeConverterTest + { + public class DateTimeTestClass + { + public string PreField; + public DateTime DateTimeField; + public string PostField; + } + + [Test] + public void Serialize() + { + DateTimeTestClass c = new DateTimeTestClass(); + c.DateTimeField = new DateTime(2008, 12, 12, 12, 12, 12, 12); + c.PreField = "Pre"; + c.PostField = "Post"; + + string json = JavaScriptConvert.SerializeObject(c, new AspNetAjaxDateTimeConverter()); + + Assert.AreEqual(@"{""PreField"":""Pre"",""DateTimeField"":""@1229083932012@"",""PostField"":""Post""}", json); + } + + [Test] + public void DeSerialize() + { + DateTimeTestClass c = + JavaScriptConvert.DeserializeObject(@"{""PreField"":""Pre"",""DateTimeField"":""@1229083932012@"",""PostField"":""Post""}", new AspNetAjaxDateTimeConverter()); + + Assert.AreEqual(new DateTime(2008, 12, 12, 12, 12, 12, 12), c.DateTimeField); + Assert.AreEqual("Pre", c.PreField); + Assert.AreEqual("Post", c.PostField); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonReaderTest.cs new file mode 100644 index 00000000..5bb32aa8 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/JsonReaderTest.cs @@ -0,0 +1,220 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json; +using System.IO; + +namespace Newtonsoft.Json.Tests +{ + [TestFixture] + public class JsonReaderTest + { + [Test] + public void YahooFinance() + { + string input = @"{ +""matches"" : [ +{""t"":""C"", ""n"":""Citigroup Inc."", ""e"":""NYSE"", ""id"":""662713""} +,{""t"":""CHL"", ""n"":""China Mobile Ltd. (ADR)"", ""e"":""NYSE"", ""id"":""660998""} +,{""t"":""PTR"", ""n"":""PetroChina Company Limited (ADR)"", ""e"":""NYSE"", ""id"":""664536""} +,{""t"":""RIO"", ""n"":""Companhia Vale do Rio Doce (ADR)"", ""e"":""NYSE"", ""id"":""671472""} +,{""t"":""RIOPR"", ""n"":""Companhia Vale do Rio Doce (ADR)"", ""e"":""NYSE"", ""id"":""3512643""} +,{""t"":""CSCO"", ""n"":""Cisco Systems, Inc."", ""e"":""NASDAQ"", ""id"":""99624""} +,{""t"":""CVX"", ""n"":""Chevron Corporation"", ""e"":""NYSE"", ""id"":""667226""} +,{""t"":""TM"", ""n"":""Toyota Motor Corporation (ADR)"", ""e"":""NYSE"", ""id"":""655880""} +,{""t"":""JPM"", ""n"":""JPMorgan Chase \x26 Co."", ""e"":""NYSE"", ""id"":""665639""} +,{""t"":""COP"", ""n"":""ConocoPhillips"", ""e"":""NYSE"", ""id"":""1691168""} +,{""t"":""LFC"", ""n"":""China Life Insurance Company Ltd. (ADR)"", ""e"":""NYSE"", ""id"":""688679""} +,{""t"":""NOK"", ""n"":""Nokia Corporation (ADR)"", ""e"":""NYSE"", ""id"":""657729""} +,{""t"":""KO"", ""n"":""The Coca-Cola Company"", ""e"":""NYSE"", ""id"":""6550""} +,{""t"":""VZ"", ""n"":""Verizon Communications Inc."", ""e"":""NYSE"", ""id"":""664887""} +,{""t"":""AMX"", ""n"":""America Movil S.A.B de C.V. (ADR)"", ""e"":""NYSE"", ""id"":""665834""}], +""all"" : false +} +"; + + using (JsonReader jsonReader = new JsonReader(new StringReader(input))) + { + while (jsonReader.Read()) + { + Console.WriteLine(jsonReader.Value); + } + } + } + + [Test] + public void ReadingIndented() + { + string input = @"{ + CPU: 'Intel', + Drives: [ + 'DVD read/writer', + ""500 gigabyte hard drive"" + ] +}"; + + StringReader sr = new StringReader(input); + + using (JsonReader jsonReader = new JsonReader(sr)) + { + Assert.AreEqual(jsonReader.TokenType, JsonToken.None); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName); + Assert.AreEqual(jsonReader.Value, "CPU"); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.String); + Assert.AreEqual(jsonReader.Value, "Intel"); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName); + Assert.AreEqual(jsonReader.Value, "Drives"); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.StartArray); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.String); + Assert.AreEqual(jsonReader.Value, "DVD read/writer"); + Assert.AreEqual(jsonReader.QuoteChar, '\''); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.String); + Assert.AreEqual(jsonReader.Value, "500 gigabyte hard drive"); + Assert.AreEqual(jsonReader.QuoteChar, '"'); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.EndArray); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject); + } + } + + [Test] + public void ReadingEscapedStrings() + { + string input = "{value:'Purple\\r \\n monkey\\'s:\\tdishwasher'}"; + + StringReader sr = new StringReader(input); + + using (JsonReader jsonReader = new JsonReader(sr)) + { + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.String); + Assert.AreEqual(jsonReader.Value, "Purple\r \n monkey's:\tdishwasher"); + Assert.AreEqual(jsonReader.QuoteChar, '\''); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject); + } + } + + [Test] + public void ReadNewlineLastCharacter() + { + string input = @"{ + CPU: 'Intel', + Drives: [ + 'DVD read/writer', + ""500 gigabyte hard drive"" + ] +}" + '\n'; + + object o = JavaScriptConvert.DeserializeObject(input); + } + + [Test] + public void WriteReadWrite() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonWriter(sw)) + { + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue(true); + + jsonWriter.WriteStartObject(); + jsonWriter.WritePropertyName("integer"); + jsonWriter.WriteValue(99); + jsonWriter.WritePropertyName("string"); + jsonWriter.WriteValue("how now brown cow?"); + jsonWriter.WritePropertyName("array"); + + jsonWriter.WriteStartArray(); + for (int i = 0; i < 5; i++) + { + jsonWriter.WriteValue(i); + } + + jsonWriter.WriteStartObject(); + jsonWriter.WritePropertyName("decimal"); + jsonWriter.WriteValue(990.00990099m); + jsonWriter.WriteEndObject(); + + jsonWriter.WriteValue(5); + jsonWriter.WriteEndArray(); + + jsonWriter.WriteEndObject(); + + jsonWriter.WriteValue("This is a string."); + jsonWriter.WriteNull(); + jsonWriter.WriteNull(); + jsonWriter.WriteEndArray(); + } + + string json = sb.ToString(); + + JsonSerializer serializer = new JsonSerializer(); + + object jsonObject = serializer.Deserialize(new JsonReader(new StringReader(json))); + + sb = new StringBuilder(); + sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonWriter(sw)) + { + serializer.Serialize(sw, jsonObject); + } + + Assert.AreEqual(json, sb.ToString()); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs new file mode 100644 index 00000000..fbbd1ce8 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs @@ -0,0 +1,529 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json; +using System.IO; +using System.Collections; +using System.Xml; +using System.Xml.Serialization; +using System.Collections.ObjectModel; + +namespace Newtonsoft.Json.Tests +{ + public class Product + { + public string Name; + public DateTime Expiry; + public decimal Price; + public string[] Sizes; + } + + public class Store + { + public StoreColor Color = StoreColor.Yellow; + public DateTime Establised = new DateTime(2010, 1, 22); + public double Width = 1.1; + public int Employees = 999; + public int[] RoomsPerFloor = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + public bool Open = false; + public char Symbol = '@'; + public List Mottos = new List(); + public decimal Cost = 100980.1M; + public string Escape = "\r\n\t\f\b?{\\r\\n\"\'"; + public List product = new List(); + + public Store() + { + Mottos.Add("Hello World"); + Mottos.Add("öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"); + Mottos.Add(null); + Mottos.Add(" "); + + Product rocket = new Product(); + rocket.Name = "Rocket"; + rocket.Expiry = new DateTime(2000, 2, 2, 23, 1, 30); + Product alien = new Product(); + alien.Name = "Alien"; + + product.Add(rocket); + product.Add(alien); + } + } + + public enum StoreColor + { + Black, + Red, + Yellow, + White + } + + [TestFixture] + public class JsonSerializerTest + { + [Test] + public void PersonTypedObjectDeserialization() + { + Store store = new Store(); + + string jsonText = JavaScriptConvert.SerializeObject(store); + + Store deserializedStore = (Store)JavaScriptConvert.DeserializeObject(jsonText, typeof(Store)); + + Console.WriteLine(jsonText); + } + + [Test] + public void TypedObjectDeserialization() + { + Product product = new Product(); + + product.Name = "Apple"; + product.Expiry = new DateTime(2008, 12, 28); + product.Price = 3.99M; + product.Sizes = new string[] { "Small", "Medium", "Large" }; + + string output = JavaScriptConvert.SerializeObject(product); + //{ + // "Name": "Apple", + // "Expiry": new Date(1230422400000), + // "Price": 3.99, + // "Sizes": [ + // "Small", + // "Medium", + // "Large" + // ] + //} + + Product deserializedProduct = (Product)JavaScriptConvert.DeserializeObject(output, typeof(Product)); + + Assert.AreEqual("Apple", deserializedProduct.Name); + Assert.AreEqual(new DateTime(2008, 12, 28), deserializedProduct.Expiry); + Assert.AreEqual(3.99, deserializedProduct.Price); + Assert.AreEqual("Small", deserializedProduct.Sizes[0]); + Assert.AreEqual("Medium", deserializedProduct.Sizes[1]); + Assert.AreEqual("Large", deserializedProduct.Sizes[2]); + } + + [Test] + public void JavaScriptConvertSerializer() + { + string value = @"{""Name"":""Orange"", ""Price"":3.99, ""Expiry"":""01/24/2010 12:00:00""}"; + + Product p = JavaScriptConvert.DeserializeObject(value, typeof(Product)) as Product; + + Assert.AreEqual("Orange", p.Name); + Assert.AreEqual(new DateTime(2010, 1, 24, 12, 0, 0), p.Expiry); + Assert.AreEqual(3.99, p.Price); + } + + [Test] + public void DeserializeJavaScriptDate() + { + DateTime dateValue = new DateTime(2000, 3, 30); + Dictionary testDictionary = new Dictionary(); + testDictionary["date"] = dateValue; + + string jsonText = JavaScriptConvert.SerializeObject(testDictionary); + + Dictionary deserializedDictionary = (Dictionary)JavaScriptConvert.DeserializeObject(jsonText, typeof(Dictionary)); + DateTime deserializedDate = (DateTime)deserializedDictionary["date"]; + + Assert.AreEqual(dateValue, deserializedDate); + + Console.WriteLine("DeserializeJavaScriptDate"); + Console.WriteLine(jsonText); + Console.WriteLine(); + Console.WriteLine(jsonText); + } + + public class MethodExecutorObject + { + public string serverClassName; + public object[] serverMethodParams; + public string clientGetResultFunction; + } + + [Test] + public void TestMethodExecutorObject() + { + MethodExecutorObject executorObject = new MethodExecutorObject(); + executorObject.serverClassName = "BanSubs"; + executorObject.serverMethodParams = new object[] { "21321546", "101", "1236", "D:\\1.txt" }; + executorObject.clientGetResultFunction = "ClientBanSubsCB"; + + string output = JavaScriptConvert.SerializeObject(executorObject); + + MethodExecutorObject executorObject2 = JavaScriptConvert.DeserializeObject(output, typeof(MethodExecutorObject)) as MethodExecutorObject; + + Assert.AreNotSame(executorObject, executorObject2); + Assert.AreEqual(executorObject2.serverClassName, "BanSubs"); + Assert.AreEqual(executorObject2.serverMethodParams.Length, 4); + Assert.Contains("101", executorObject2.serverMethodParams); + Assert.AreEqual(executorObject2.clientGetResultFunction, "ClientBanSubsCB"); + } + + [Test] + public void HashtableDeserialization() + { + string value = @"{""Name"":""Orange"", ""Price"":3.99, ""Expiry"":""01/24/2010 12:00:00""}"; + + Hashtable p = JavaScriptConvert.DeserializeObject(value, typeof(Hashtable)) as Hashtable; + + Assert.AreEqual("Orange", p["Name"].ToString()); + } + + public class TypedSubHashtable + { + public string Name; + public Hashtable Hash; + } + + [Test] + public void TypedHashtableDeserialization() + { + string value = @"{""Name"":""Orange"", ""Hash"":{""Expiry"":""01/24/2010 12:00:00""}}"; + + TypedSubHashtable p = JavaScriptConvert.DeserializeObject(value, typeof(TypedSubHashtable)) as TypedSubHashtable; + + Assert.AreEqual("01/24/2010 12:00:00", p.Hash["Expiry"].ToString()); + } + + public class GetOnlyPropertyClass + { + public string Field = "Field"; + + public string GetOnlyProperty + { + get { return "GetOnlyProperty"; } + } + } + + [Test] + public void SerializeDeserializeGetOnlyProperty() + { + string value = JavaScriptConvert.SerializeObject(new GetOnlyPropertyClass()); + + GetOnlyPropertyClass c = JavaScriptConvert.DeserializeObject(value); + + Assert.AreEqual(c.Field, "Field"); + Assert.AreEqual(c.GetOnlyProperty, "GetOnlyProperty"); + } + + public class SetOnlyPropertyClass + { + public string Field = "Field"; + + public string SetOnlyProperty + { + set { } + } + } + + [Test] + public void SerializeDeserializeSetOnlyProperty() + { + string value = JavaScriptConvert.SerializeObject(new SetOnlyPropertyClass()); + + SetOnlyPropertyClass c = JavaScriptConvert.DeserializeObject(value); + + Assert.AreEqual(c.Field, "Field"); + } + + public class JsonIgnoreAttributeTestClass + { + private int _property = 21; + private int _ignoredProperty = 12; + + public int Field; + public int Property + { + get { return _property; } + } + + [JsonIgnore] + public int IgnoredField; + + [JsonIgnore] + public int IgnoredProperty + { + get { return _ignoredProperty; } + } + } + + [Test] + public void JsonIgnoreAttributeTest() + { + string json = JavaScriptConvert.SerializeObject(new JsonIgnoreAttributeTestClass()); + + Assert.AreEqual(@"{""Field"":0,""Property"":21}", json); + + JsonIgnoreAttributeTestClass c = JavaScriptConvert.DeserializeObject(@"{""Field"":99,""Property"":-1,""IgnoredField"":-1}"); + + Assert.AreEqual(0, c.IgnoredField); + Assert.AreEqual(99, c.Field); + } + + [Test] + public void GoogleSearchAPI() + { + string json = @"{ + results: + [ + { + GsearchResultClass:""GwebSearch"", + unescapedUrl : ""http://www.google.com/"", + url : ""http://www.google.com/"", + visibleUrl : ""www.google.com"", + cacheUrl : +""http://www.google.com/search?q=cache:zhool8dxBV4J:www.google.com"", + title : ""Google"", + titleNoFormatting : ""Google"", + content : ""Enables users to search the Web, Usenet, and +images. Features include PageRank, caching and translation of +results, and an option to find similar pages."" + }, + { + GsearchResultClass:""GwebSearch"", + unescapedUrl : ""http://news.google.com/"", + url : ""http://news.google.com/"", + visibleUrl : ""news.google.com"", + cacheUrl : +""http://www.google.com/search?q=cache:Va_XShOz_twJ:news.google.com"", + title : ""Google News"", + titleNoFormatting : ""Google News"", + content : ""Aggregated headlines and a search engine of many of the world's news sources."" + }, + + { + GsearchResultClass:""GwebSearch"", + unescapedUrl : ""http://groups.google.com/"", + url : ""http://groups.google.com/"", + visibleUrl : ""groups.google.com"", + cacheUrl : +""http://www.google.com/search?q=cache:x2uPD3hfkn0J:groups.google.com"", + title : ""Google Groups"", + titleNoFormatting : ""Google Groups"", + content : ""Enables users to search and browse the Usenet +archives which consist of over 700 million messages, and post new +comments."" + }, + + { + GsearchResultClass:""GwebSearch"", + unescapedUrl : ""http://maps.google.com/"", + url : ""http://maps.google.com/"", + visibleUrl : ""maps.google.com"", + cacheUrl : +""http://www.google.com/search?q=cache:dkf5u2twBXIJ:maps.google.com"", + title : ""Google Maps"", + titleNoFormatting : ""Google Maps"", + content : ""Provides directions, interactive maps, and +satellite/aerial imagery of the United States. Can also search by +keyword such as type of business."" + } + ], + + adResults: + [ + { + GsearchResultClass:""GwebSearch.ad"", + title : ""Gartner Symposium/ITxpo"", + content1 : ""Meet brilliant Gartner IT analysts"", + content2 : ""20-23 May 2007- Barcelona, Spain"", + url : +""http://www.google.com/url?sa=L&ai=BVualExYGRo3hD5ianAPJvejjD8-s6ye7kdTwArbI4gTAlrECEAEYASDXtMMFOAFQubWAjvr_____AWDXw_4EiAEBmAEAyAEBgAIB&num=1&q=http://www.gartner.com/it/sym/2007/spr8/spr8.jsp%3Fsrc%3D_spain_07_%26WT.srch%3D1&usg=__CxRH06E4Xvm9Muq13S4MgMtnziY="", + + impressionUrl : +""http://www.google.com/uds/css/ad-indicator-on.gif?ai=BVualExYGRo3hD5ianAPJvejjD8-s6ye7kdTwArbI4gTAlrECEAEYASDXtMMFOAFQubWAjvr_____AWDXw_4EiAEBmAEAyAEBgAIB"", + + unescapedUrl : +""http://www.google.com/url?sa=L&ai=BVualExYGRo3hD5ianAPJvejjD8-s6ye7kdTwArbI4gTAlrECEAEYASDXtMMFOAFQubWAjvr_____AWDXw_4EiAEBmAEAyAEBgAIB&num=1&q=http://www.gartner.com/it/sym/2007/spr8/spr8.jsp%3Fsrc%3D_spain_07_%26WT.srch%3D1&usg=__CxRH06E4Xvm9Muq13S4MgMtnziY="", + + visibleUrl : ""www.gartner.com"" + } + ] +} +"; + object o = JavaScriptConvert.DeserializeObject(json); + string s = string.Empty; + s += s; + } + + [Test] + public void TorrentDeserializeTest() + { + string jsonText = @"{ +"""":"""", +""label"": [ + [""SomeName"",6] +], +""torrents"": [ + [""192D99A5C943555CB7F00A852821CF6D6DB3008A"",201,""filename.avi"",178311826,1000,178311826,72815250,408,1603,7,121430,""NameOfLabelPrevioslyDefined"",3,6,0,8,128954,-1,0], +], +""torrentc"": ""1816000723"" +}"; + + JavaScriptObject o = (JavaScriptObject)JavaScriptConvert.DeserializeObject(jsonText); + Assert.AreEqual(4, o.Count); + + JavaScriptArray torrentsArray = (JavaScriptArray)o["torrents"]; + JavaScriptArray nestedTorrentsArray = (JavaScriptArray)torrentsArray[0]; + Assert.AreEqual(nestedTorrentsArray.Count, 19); + } + + public class JsonPropertyClass + { + [JsonProperty("pie")] + public string Pie = "Yum"; + + [JsonIgnore] + public string pie = "No pie for you!"; + + public string pie1 = "PieChart!"; + + private int _sweetCakesCount; + + [JsonProperty("sweet_cakes_count")] + public int SweetCakesCount + { + get { return _sweetCakesCount; } + set { _sweetCakesCount = value; } + } + } + + [Test] + public void JsonPropertyClassSerialize() + { + JsonPropertyClass test = new JsonPropertyClass(); + test.Pie = "Delicious"; + test.SweetCakesCount = int.MaxValue; + + string jsonText = JavaScriptConvert.SerializeObject(test); + + Assert.AreEqual(@"{""pie"":""Delicious"",""pie1"":""PieChart!"",""sweet_cakes_count"":2147483647}", jsonText); + + JsonPropertyClass test2 = JavaScriptConvert.DeserializeObject(jsonText); + + Assert.AreEqual(test.Pie, test2.Pie); + Assert.AreEqual(test.SweetCakesCount, test2.SweetCakesCount); + } + + public class BadJsonPropertyClass + { + [JsonProperty("pie")] + public string Pie = "Yum"; + + public string pie = "PieChart!"; + } + + [Test] + [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"A member with the name 'pie' already exists on Newtonsoft.Json.Tests.JsonSerializerTest+BadJsonPropertyClass. Use the JsonPropertyAttribute to specify another name.")] + public void BadJsonPropertyClassSerialize() + { + JavaScriptConvert.SerializeObject(new BadJsonPropertyClass()); + } + + public class Article + { + public string Name; + + public Article() + { + } + + public Article(string name) + { + Name = name; + } + } + + public class ArticleCollection : List
+ { + } + + [Test] + public void InheritedListSerialize() + { + Article a1 = new Article("a1"); + Article a2 = new Article("a2"); + + ArticleCollection articles1 = new ArticleCollection(); + articles1.Add(a1); + articles1.Add(a2); + + string jsonText = JavaScriptConvert.SerializeObject(articles1); + + ArticleCollection articles2 = JavaScriptConvert.DeserializeObject(jsonText); + + Assert.AreEqual(articles1.Count, articles2.Count); + Assert.AreEqual(articles1[0].Name, articles2[0].Name); + } + + [Test] + public void ReadOnlyCollectionSerialize() + { + ReadOnlyCollection r1 = new ReadOnlyCollection(new int[] {0, 1, 2, 3, 4}); + + string jsonText = JavaScriptConvert.SerializeObject(r1); + + ReadOnlyCollection r2 = JavaScriptConvert.DeserializeObject>(jsonText); + + CollectionAssert.AreEqual(r1, r2); + } + + //public abstract class Foo + //{ + //} + + //public class Baz : Foo + //{ + //} + + //public class Bar : Foo + //{ + //} + + //public class BazJsonConverter : JsonConverter + //{ + // public override bool CanConvert(Type objectType) + // { + // throw new Exception("The method or operation is not implemented."); + // } + //} + + //public class BarJsonConverter : JsonConverter + //{ + // public override bool CanConvert(Type objectType) + // { + // throw new Exception("The method or operation is not implemented."); + // } + //} + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonWriterTest.cs new file mode 100644 index 00000000..5bb8aeb7 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/JsonWriterTest.cs @@ -0,0 +1,176 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json; +using System.IO; + +namespace Newtonsoft.Json.Tests +{ + [TestFixture] + public class JsonWriterTest + { + [Test] + public void ValueFormatting() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonWriter(sw)) + { + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue('@'); + jsonWriter.WriteValue("\r\n\t\f\b?{\\r\\n\"\'"); + jsonWriter.WriteValue(true); + jsonWriter.WriteValue(10); + jsonWriter.WriteValue(10.99); + jsonWriter.WriteValue(0.99); + jsonWriter.WriteValue(0.000000000000000001d); + jsonWriter.WriteValue(0.000000000000000001m); + jsonWriter.WriteValue(null); + jsonWriter.WriteValue("This is a string."); + jsonWriter.WriteNull(); + jsonWriter.WriteUndefined(); + jsonWriter.WriteEndArray(); + } + + string expected = @"[""@"",""\r\n\t\f\b?{\\r\\n\""'"",true,10,10.99,0.99,1E-18,0.000000000000000001,"""",""This is a string."",null,undefined]"; + string result = sb.ToString(); + + Console.WriteLine("ValueFormatting"); + Console.WriteLine(result); + + Assert.AreEqual(expected, result); + } + + [Test] + public void StringEscaping() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonWriter(sw)) + { + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue(@"""These pretzels are making me thirsty!"""); + jsonWriter.WriteValue("Jeff's house was burninated."); + jsonWriter.WriteValue(@"1. You don't talk about fight club. +2. You don't talk about fight club."); + jsonWriter.WriteValue("35% of\t statistics\n are made\r up."); + jsonWriter.WriteEndArray(); + } + + string expected = @"[""\""These pretzels are making me thirsty!\"""",""Jeff's house was burninated."",""1. You don't talk about fight club.\r\n2. You don't talk about fight club."",""35% of\t statistics\n are made\r up.""]"; + string result = sb.ToString(); + + Console.WriteLine("StringEscaping"); + Console.WriteLine(result); + + Assert.AreEqual(expected, result); + } + + [Test] + public void Indenting() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonWriter(sw)) + { + jsonWriter.Formatting = Formatting.Indented; + + jsonWriter.WriteStartObject(); + jsonWriter.WritePropertyName("CPU"); + jsonWriter.WriteValue("Intel"); + jsonWriter.WritePropertyName("PSU"); + jsonWriter.WriteValue("500W"); + jsonWriter.WritePropertyName("Drives"); + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue("DVD read/writer"); + jsonWriter.WriteComment("(broken)"); + jsonWriter.WriteValue("500 gigabyte hard drive"); + jsonWriter.WriteValue("200 gigabype hard drive"); + jsonWriter.WriteEnd(); + jsonWriter.WriteEndObject(); + } + + string expected = @"{ + ""CPU"": ""Intel"", + ""PSU"": ""500W"", + ""Drives"": [ + ""DVD read/writer"" + /*(broken)*/, + ""500 gigabyte hard drive"", + ""200 gigabype hard drive"" + ] +}"; + string result = sb.ToString(); + + Console.WriteLine("Indenting"); + Console.WriteLine(result); + + Assert.AreEqual(expected, result); + } + + [Test] + public void State() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonWriter(sw)) + { + Assert.AreEqual(WriteState.Start, jsonWriter.WriteState); + + jsonWriter.WriteStartObject(); + Assert.AreEqual(WriteState.Object, jsonWriter.WriteState); + + jsonWriter.WritePropertyName("CPU"); + Assert.AreEqual(WriteState.Property, jsonWriter.WriteState); + + jsonWriter.WriteValue("Intel"); + Assert.AreEqual(WriteState.Object, jsonWriter.WriteState); + + jsonWriter.WritePropertyName("Drives"); + Assert.AreEqual(WriteState.Property, jsonWriter.WriteState); + + jsonWriter.WriteStartArray(); + Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); + + jsonWriter.WriteValue("DVD read/writer"); + Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); + + jsonWriter.WriteEnd(); + Assert.AreEqual(WriteState.Object, jsonWriter.WriteState); + + jsonWriter.WriteEndObject(); + Assert.AreEqual(WriteState.Start, jsonWriter.WriteState); + } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj new file mode 100644 index 00000000..a1bb2c48 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -0,0 +1,69 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {3E6E2335-B079-4B5B-A65A-9D586914BCBB} + Library + Properties + Newtonsoft.Json.Tests + Newtonsoft.Json.Tests + + + + + + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\Lib\nunit.framework.dll + + + + + + + + + + + + + + + + {A9AE40FF-1A21-414A-9FE7-3BE13644CC6D} + Newtonsoft.Json + + + + + \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..0fc1b845 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +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("Newtonsoft Json.NET Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Newtonsoft")] +[assembly: AssemblyProduct("Newtonsoft Json.NET Test")] +[assembly: AssemblyCopyright("Copyright © Newtonsoft 2006")] +[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("0be3d72b-d2ef-409c-985c-d3ede89a25f1")] + +// 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.3.0.0")] +[assembly: AssemblyFileVersion("1.3.0.0")] diff --git a/Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs new file mode 100644 index 00000000..ac75d3df --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs @@ -0,0 +1,342 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using NUnit.Framework; +using Newtonsoft.Json; +using System.IO; +using System.Xml; +using Newtonsoft.Json.Converters; + +namespace Newtonsoft.Json.Tests +{ + [TestFixture] + public class XmlNodeConverterTest + { + [Test] + public void DocumentSerializeIndented() + { + string xml = @" + + + + Web 2.0 Conference + October 5 + 7 + Argent Hotel, San Francisco, CA + +"; + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + + StringWriter sw = new StringWriter(); + + using (JsonWriter jsonWriter = new JsonWriter(sw)) + { + jsonWriter.Formatting = Formatting.Indented; + + JsonSerializer jsonSerializer = new JsonSerializer(); + jsonSerializer.Converters.Add(new XmlNodeConverter()); + + jsonSerializer.Serialize(jsonWriter, doc); + } + + string jsonText = sw.ToString(); + string expected = @"{ + ""?xml"": { + ""@version"": ""1.0"", + ""@standalone"": ""no"" + }, + ""?xml-stylesheet"": ""href=\""classic.xsl\"" type=\""text/xml\"""", + ""span"": { + ""@class"": ""vevent"", + ""a"": { + ""@class"": ""url"", + ""@href"": ""http://www.web2con.com/"", + ""span"": [ + { + ""@class"": ""summary"", + ""#text"": ""Web 2.0 Conference"", + ""#cdata-section"": ""my escaped text"" + }, + { + ""@class"": ""location"", + ""#text"": ""Argent Hotel, San Francisco, CA"" + } + ], + ""abbr"": [ + { + ""@class"": ""dtstart"", + ""@title"": ""2005-10-05"", + ""#text"": ""October 5"" + }, + { + ""@class"": ""dtend"", + ""@title"": ""2005-10-08"", + ""#text"": ""7"" + } + ] + } + } +}"; + + Assert.AreEqual(expected, jsonText); + + Console.WriteLine("DocumentSerializeIndented"); + Console.WriteLine(jsonText); + Console.WriteLine(); + } + + [Test] + public void SerializeNodeTypes() + { + XmlDocument doc = new XmlDocument(); + string jsonText; + + Console.WriteLine("SerializeNodeTypes"); + + // XmlAttribute + XmlAttribute attribute = doc.CreateAttribute("msdata:IsDataSet"); + attribute.Value = "true"; + + jsonText = JavaScriptConvert.SerializeXmlNode(attribute); + + Console.WriteLine(jsonText); + Assert.AreEqual(@"{""@msdata:IsDataSet"":""true""}", jsonText); + + + // XmlProcessingInstruction + XmlProcessingInstruction instruction = doc.CreateProcessingInstruction("xml-stylesheet", @"href=""classic.xsl"" type=""text/xml"""); + + jsonText = JavaScriptConvert.SerializeXmlNode(instruction); + + Console.WriteLine(jsonText); + Assert.AreEqual(@"{""?xml-stylesheet"":""href=\""classic.xsl\"" type=\""text/xml\""""}", jsonText); + + + // XmlProcessingInstruction + XmlCDataSection cDataSection = doc.CreateCDataSection("true"); + + jsonText = JavaScriptConvert.SerializeXmlNode(cDataSection); + + Console.WriteLine(jsonText); + Assert.AreEqual(@"{""#cdata-section"":""true""}", jsonText); + + + // XmlElement + XmlElement element = doc.CreateElement("xs:Choice"); + element.SetAttributeNode(attribute); + + element.AppendChild(instruction); + element.AppendChild(cDataSection); + + jsonText = JavaScriptConvert.SerializeXmlNode(element); + + Console.WriteLine(jsonText); + Assert.AreEqual(@"{""xs:Choice"":{""@msdata:IsDataSet"":""true"",""?xml-stylesheet"":""href=\""classic.xsl\"" type=\""text/xml\"""",""#cdata-section"":""true""}}", jsonText); + } + + [Test] + public void DocumentFragmentSerialize() + { + XmlDocument doc = new XmlDocument(); + + XmlDocumentFragment fragement = doc.CreateDocumentFragment(); + + fragement.InnerXml = "widgetwidget"; + + string jsonText = JavaScriptConvert.SerializeXmlNode(fragement); + + string expected = @"{""Item"":[""widget"",""widget""]}"; + + Assert.AreEqual(expected, jsonText); + + Console.WriteLine("DocumentFragmentSerialize"); + Console.WriteLine(jsonText); + Console.WriteLine(); + } + + [Test] + public void NamespaceSerializeDeserialize() + { + string xml = @" + + + + + + + + + + + + + + + + +"; + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + + string jsonText = JavaScriptConvert.SerializeXmlNode(doc); + + XmlDocument deserializedDoc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText); + + Assert.AreEqual(doc.InnerXml, deserializedDoc.InnerXml); + + Console.WriteLine("NamespaceSerializeDeserialize"); + Console.WriteLine(jsonText); + Console.WriteLine(deserializedDoc.InnerXml); + Console.WriteLine(); + } + + [Test] + public void DocumentDeserialize() + { + string jsonText = @"{ + ""?xml"": { + ""@version"": ""1.0"", + ""@standalone"": ""no"" + }, + ""span"": { + ""@class"": ""vevent"", + ""a"": { + ""@class"": ""url"", + ""@href"": ""http://www.web2con.com/"", + ""span"": { + ""@class"": ""summary"", + ""#text"": ""Web 2.0 Conference"", + ""#cdata-section"": ""my escaped text"" + } + } + } +}"; + + XmlDocument doc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText); + + string expected = @" + + + Web 2.0 Conference + +"; + + string formattedXml = GetIndentedInnerXml(doc); + + Console.WriteLine("DocumentDeserialize"); + Console.WriteLine(formattedXml); + Console.WriteLine(); + + Assert.AreEqual(expected, formattedXml); + } + + private string GetIndentedInnerXml(XmlNode node) + { + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Indent = true; + + StringWriter sw = new StringWriter(); + + using (XmlWriter writer = XmlWriter.Create(sw, settings)) + { + node.WriteTo(writer); + } + + return sw.ToString(); + } + + [Test] + public void SingleTextNode() + { + string xml = @" + + + Alan + http://www.google.com + + + Louis + http://www.yahoo.com + + "; + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + + string jsonText = JavaScriptConvert.SerializeXmlNode(doc); + + XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText); + + Assert.AreEqual(doc.InnerXml, newDoc.InnerXml); + } + + [Test] + public void EmptyNode() + { + string xml = @" + + + Alan + + + + Louis + http://www.yahoo.com + + "; + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + + string jsonText = JavaScriptConvert.SerializeXmlNode(doc); + + Console.WriteLine(jsonText); + + XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText); + + Assert.AreEqual(doc.InnerXml, newDoc.InnerXml); + } + + [Test] + public void OtherElementDataTypes() + { + string jsonText = @"{""?xml"":{""@version"":""1.0"",""@standalone"":""no""},""root"":{""person"":[{""@id"":""1"",""Float"":2.5,""Integer"":99},{""@id"":""2"",""Boolean"":true,""date"":new Date(954374400000)}]}}"; + + XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText); + + string expected = @"2.599true2000-03-30T00:00:00.0000000+12:00"; + + Assert.AreEqual(expected, newDoc.InnerXml); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.sln b/Src/Newtonsoft.Json.sln new file mode 100644 index 00000000..9f268d1d --- /dev/null +++ b/Src/Newtonsoft.Json.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Newtonsoft.Json", "Newtonsoft.Json\Newtonsoft.Json.csproj", "{A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{620042D9-2753-48F5-BEDE-3905248781D2}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(SolutionItems) = preProject + Lib\nunit.framework.dll = Lib\nunit.framework.dll + Lib\nunit.framework.xml = Lib\nunit.framework.xml + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Newtonsoft.Json.Tests", "Newtonsoft.Json.Tests\Newtonsoft.Json.Tests.csproj", "{3E6E2335-B079-4B5B-A65A-9D586914BCBB}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}.Release|Any CPU.Build.0 = Release|Any CPU + {3E6E2335-B079-4B5B-A65A-9D586914BCBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E6E2335-B079-4B5B-A65A-9D586914BCBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E6E2335-B079-4B5B-A65A-9D586914BCBB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E6E2335-B079-4B5B-A65A-9D586914BCBB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Src/Newtonsoft.Json/Converters/AspNetAjaxDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/AspNetAjaxDateTimeConverter.cs new file mode 100644 index 00000000..eaaf83fa --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/AspNetAjaxDateTimeConverter.cs @@ -0,0 +1,59 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + + +using System; +using System.Collections.Generic; +using System.Text; +using System.Globalization; + +namespace Newtonsoft.Json.Converters +{ + public class AspNetAjaxDateTimeConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value) + { + DateTime dateTime = (DateTime)value; + long javaScriptTicks = JavaScriptConvert.ConvertDateTimeToJavaScriptTicks(dateTime); + + writer.WriteValue("@" + javaScriptTicks.ToString(null, CultureInfo.InvariantCulture) + "@"); + } + + public override object ReadJson(JsonReader reader, Type objectType) + { + string dateTimeText = (string)reader.Value; + dateTimeText = dateTimeText.Substring(1, dateTimeText.Length - 2); + + long javaScriptTicks = Convert.ToInt64(dateTimeText); + + return JavaScriptConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks); + } + + public override bool CanConvert(Type valueType) + { + return typeof(DateTime).IsAssignableFrom(valueType); + } + } +} diff --git a/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs b/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs new file mode 100644 index 00000000..434146ee --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs @@ -0,0 +1,45 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace Newtonsoft.Json.Converters +{ + public class HtmlColorConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value) + { + writer.WriteValue(ColorTranslator.ToHtml((Color)value)); + } + + public override bool CanConvert(Type valueType) + { + return typeof(Color).IsAssignableFrom(valueType); + } + } +} diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs new file mode 100644 index 00000000..27758213 --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -0,0 +1,472 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Xml; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Converters +{ + public class XmlNodeConverter : JsonConverter + { + private const string TextName = "#text"; + private const string CommentName = "#comment"; + private const string CDataName = "#cdata-section"; + private const string WhitespaceName = "#whitespace"; + private const string SignificantWhitespaceName = "#significant-whitespace"; + private const string DeclarationName = "?xml"; + + #region Writing + public override void WriteJson(JsonWriter writer, object value) + { + XmlNode node = value as XmlNode; + + if (node == null) + throw new ArgumentException("Value must be an XmlNode", "value"); + + writer.WriteStartObject(); + SerializeNode(writer, node, true); + writer.WriteEndObject(); + } + + private string GetPropertyName(XmlNode node) + { + switch (node.NodeType) + { + case XmlNodeType.Attribute: + return "@" + node.Name; + case XmlNodeType.CDATA: + return CDataName; + case XmlNodeType.Comment: + return CommentName; + case XmlNodeType.Element: + return node.Name; + case XmlNodeType.ProcessingInstruction: + return "?" + node.Name; + case XmlNodeType.XmlDeclaration: + return DeclarationName; + case XmlNodeType.SignificantWhitespace: + return SignificantWhitespaceName; + case XmlNodeType.Text: + return TextName; + case XmlNodeType.Whitespace: + return WhitespaceName; + default: + throw new JsonSerializationException("Unexpected XmlNodeType when getting node name: " + node.NodeType); + } + } + + private void SerializeGroupedNodes(JsonWriter writer, XmlNode node) + { + // group nodes together by name + Dictionary> nodesGroupedByName = new Dictionary>(); + + for (int i = 0; i < node.ChildNodes.Count; i++) + { + XmlNode childNode = node.ChildNodes[i]; + string nodeName = GetPropertyName(childNode); + + List nodes; + if (!nodesGroupedByName.TryGetValue(nodeName, out nodes)) + { + nodes = new List(); + nodesGroupedByName.Add(nodeName, nodes); + } + + nodes.Add(childNode); + } + + // loop through grouped nodes. write single name instances as normal, + // write multiple names together in an array + foreach (KeyValuePair> nodeNameGroup in nodesGroupedByName) + { + List groupedNodes = nodeNameGroup.Value; + + if (groupedNodes.Count == 1) + { + SerializeNode(writer, groupedNodes[0], true); + } + else + { + writer.WritePropertyName(nodeNameGroup.Key); + writer.WriteStartArray(); + + for (int i = 0; i < groupedNodes.Count; i++) + { + SerializeNode(writer, groupedNodes[i], false); + } + + writer.WriteEndArray(); + } + } + } + + private void SerializeNode(JsonWriter writer, XmlNode node, bool writePropertyName) + { + switch (node.NodeType) + { + case XmlNodeType.Document: + case XmlNodeType.DocumentFragment: + SerializeGroupedNodes(writer, node); + break; + case XmlNodeType.Element: + if (writePropertyName) + writer.WritePropertyName(node.Name); + + if (CollectionUtils.IsNullOrEmpty(node.Attributes) && node.ChildNodes.Count == 1 + && node.ChildNodes[0].NodeType == XmlNodeType.Text) + { + // write elements with a single text child as a name value pair + writer.WriteValue(node.ChildNodes[0].Value); + } + else if (node.ChildNodes.Count == 0 && CollectionUtils.IsNullOrEmpty(node.Attributes)) + { + // empty element + writer.WriteNull(); + } + else + { + writer.WriteStartObject(); + + for (int i = 0; i < node.Attributes.Count; i++) + { + SerializeNode(writer, node.Attributes[i], true); + } + + SerializeGroupedNodes(writer, node); + + writer.WriteEndObject(); + } + + break; + case XmlNodeType.Comment: + if (writePropertyName) + writer.WriteComment(node.Value); + break; + case XmlNodeType.Attribute: + case XmlNodeType.Text: + case XmlNodeType.CDATA: + case XmlNodeType.ProcessingInstruction: + case XmlNodeType.Whitespace: + case XmlNodeType.SignificantWhitespace: + if (writePropertyName) + writer.WritePropertyName(GetPropertyName(node)); + writer.WriteValue(node.Value); + break; + case XmlNodeType.XmlDeclaration: + XmlDeclaration declaration = (XmlDeclaration)node; + writer.WritePropertyName(GetPropertyName(node)); + writer.WriteStartObject(); + + if (!string.IsNullOrEmpty(declaration.Version)) + { + writer.WritePropertyName("@version"); + writer.WriteValue(declaration.Version); + } + if (!string.IsNullOrEmpty(declaration.Encoding)) + { + writer.WritePropertyName("@encoding"); + writer.WriteValue(declaration.Encoding); + } + if (!string.IsNullOrEmpty(declaration.Standalone)) + { + writer.WritePropertyName("@standalone"); + writer.WriteValue(declaration.Standalone); + } + + writer.WriteEndObject(); + break; + default: + throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType); + } + } + #endregion + + #region Reading + public override object ReadJson(JsonReader reader, Type objectType) + { + // maybe have CanReader and a CanWrite methods so this sort of test wouldn't be necessary + if (objectType != typeof(XmlDocument)) + throw new JsonSerializationException("XmlNodeConverter only supports deserializing XmlDocuments"); + + XmlDocument document = new XmlDocument(); + XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable); + reader.Read(); + + DeserializeNode(reader, document, manager, document); + + return document; + } + + private void DeserializeValue(JsonReader reader, XmlDocument document, XmlNamespaceManager manager, string propertyName, XmlNode currentNode) + { + switch (propertyName) + { + case TextName: + currentNode.AppendChild(document.CreateTextNode(reader.Value.ToString())); + break; + case CDataName: + currentNode.AppendChild(document.CreateCDataSection(reader.Value.ToString())); + break; + case WhitespaceName: + currentNode.AppendChild(document.CreateWhitespace(reader.Value.ToString())); + break; + case SignificantWhitespaceName: + currentNode.AppendChild(document.CreateSignificantWhitespace(reader.Value.ToString())); + break; + default: + // processing instructions and the xml declaration start with ? + if (propertyName[0] == '?') + { + if (propertyName == DeclarationName) + { + string version = null; + string encoding = null; + string standalone = null; + while (reader.Read() && reader.TokenType != JsonToken.EndObject) + { + switch (reader.Value.ToString()) + { + case "@version": + reader.Read(); + version = reader.Value.ToString(); + break; + case "@encoding": + reader.Read(); + encoding = reader.Value.ToString(); + break; + case "@standalone": + reader.Read(); + standalone = reader.Value.ToString(); + break; + default: + throw new JsonSerializationException("Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value); + } + } + + XmlDeclaration declaration = document.CreateXmlDeclaration(version, encoding, standalone); + currentNode.AppendChild(declaration); + } + else + { + XmlProcessingInstruction instruction = document.CreateProcessingInstruction(propertyName.Substring(1), reader.Value.ToString()); + currentNode.AppendChild(instruction); + } + } + else + { + // deserialize xml element + bool finishedAttributes = false; + bool finishedElement = false; + string elementPrefix = GetPrefix(propertyName); + Dictionary attributeNameValues = new Dictionary(); + + // a string token means the element only has a single text child + if (reader.TokenType != JsonToken.String + && reader.TokenType != JsonToken.Null + && reader.TokenType != JsonToken.Boolean + && reader.TokenType != JsonToken.Integer + && reader.TokenType != JsonToken.Float + && reader.TokenType != JsonToken.Date) + { + // read properties until first non-attribute is encountered + while (!finishedAttributes && !finishedElement && reader.Read()) + { + switch (reader.TokenType) + { + case JsonToken.PropertyName: + string attributeName = reader.Value.ToString(); + + if (attributeName[0] == '@') + { + attributeName = attributeName.Substring(1); + reader.Read(); + string attributeValue = reader.Value.ToString(); + attributeNameValues.Add(attributeName, attributeValue); + + string namespacePrefix; + + if (IsNamespaceAttribute(attributeName, out namespacePrefix)) + { + manager.AddNamespace(namespacePrefix, attributeValue); + } + } + else + { + finishedAttributes = true; + } + break; + case JsonToken.EndObject: + finishedElement = true; + break; + default: + throw new JsonSerializationException("Unexpected JsonToken: " + reader.TokenType); + } + } + } + + // have to wait until attributes have been parsed before creating element + // attributes may contain namespace info used by the element + XmlElement element = (!string.IsNullOrEmpty(elementPrefix)) + ? document.CreateElement(propertyName, manager.LookupNamespace(elementPrefix)) + : document.CreateElement(propertyName); + + currentNode.AppendChild(element); + + // add attributes to newly created element + foreach (KeyValuePair nameValue in attributeNameValues) + { + string attributePrefix = GetPrefix(nameValue.Key); + + XmlAttribute attribute = (!string.IsNullOrEmpty(attributePrefix)) + ? document.CreateAttribute(nameValue.Key, manager.LookupNamespace(attributePrefix)) + : document.CreateAttribute(nameValue.Key); + + attribute.Value = nameValue.Value; + + element.SetAttributeNode(attribute); + } + + if (reader.TokenType == JsonToken.String) + { + element.AppendChild(document.CreateTextNode(reader.Value.ToString())); + } + else if (reader.TokenType == JsonToken.Integer) + { + element.AppendChild(document.CreateTextNode(XmlConvert.ToString((long)reader.Value))); + } + else if (reader.TokenType == JsonToken.Float) + { + element.AppendChild(document.CreateTextNode(XmlConvert.ToString((double)reader.Value))); + } + else if (reader.TokenType == JsonToken.Boolean) + { + element.AppendChild(document.CreateTextNode(XmlConvert.ToString((bool)reader.Value))); + } + else if (reader.TokenType == JsonToken.Date) + { + element.AppendChild(document.CreateTextNode(XmlConvert.ToString((DateTime)reader.Value))); + } + else if (reader.TokenType == JsonToken.Null) + { + // empty element. do nothing + } + else + { + // finished element will have no children to deserialize + if (!finishedElement) + { + manager.PushScope(); + + DeserializeNode(reader, document, manager, element); + + manager.PopScope(); + } + } + } + break; + } + } + + private void DeserializeNode(JsonReader reader, XmlDocument document, XmlNamespaceManager manager, XmlNode currentNode) + { + do + { + switch (reader.TokenType) + { + case JsonToken.PropertyName: + string propertyName = reader.Value.ToString(); + reader.Read(); + + if (reader.TokenType == JsonToken.StartArray) + { + while (reader.Read() && reader.TokenType != JsonToken.EndArray) + { + DeserializeValue(reader, document, manager, propertyName, currentNode); + } + } + else + { + DeserializeValue(reader, document, manager, propertyName, currentNode); + } + break; + //case JsonToken.String: + // DeserializeValue(reader, document, manager, TextName, currentNode); + // break; + case JsonToken.EndObject: + case JsonToken.EndArray: + return; + default: + throw new JsonSerializationException("Unexpected JsonToken when deserializing node: " + reader.TokenType); + } + } while (reader.TokenType == JsonToken.PropertyName || reader.Read()); + // don't read if current token is a property. token was already read when parsing element attributes + } + + /// + /// Checks if the attributeName is a namespace attribute. + /// + /// Attribute name to test. + /// The attribute name prefix if it has one, otherwise an empty string. + /// True if attribute name is for a namespace attribute, otherwise false. + private bool IsNamespaceAttribute(string attributeName, out string prefix) + { + if (attributeName.StartsWith("xmlns", StringComparison.Ordinal)) + { + if (attributeName.Length == 5) + { + prefix = string.Empty; + return true; + } + else if (attributeName[5] == ':') + { + prefix = attributeName.Substring(6, attributeName.Length - 6); + return true; + } + } + prefix = null; + return false; + } + + private string GetPrefix(string qualifiedName) + { + int colonPosition = qualifiedName.IndexOf(':'); + + if ((colonPosition == -1 || colonPosition == 0) || (qualifiedName.Length - 1) == colonPosition) + return string.Empty; + else + return qualifiedName.Substring(0, colonPosition); + } + #endregion + + public override bool CanConvert(Type valueType) + { + return typeof(XmlNode).IsAssignableFrom(valueType); + } + } +} diff --git a/Src/Newtonsoft.Json/Identifier.cs b/Src/Newtonsoft.Json/Identifier.cs new file mode 100644 index 00000000..b74df378 --- /dev/null +++ b/Src/Newtonsoft.Json/Identifier.cs @@ -0,0 +1,102 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections; +using System.Globalization; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using System.Web; +using System.Collections.Generic; +using System.Drawing; +using System.Web.UI.WebControls; +using System.ComponentModel; + +namespace Newtonsoft.Json +{ + public class Identifier + { + private string _name; + + public string Name + { + get { return _name; } + } + + public Identifier(string name) + { + _name = name; + } + + private static bool IsAsciiLetter(char c) + { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } + + public override bool Equals(object obj) + { + Identifier function = obj as Identifier; + + return Equals(function); + } + + public bool Equals(Identifier function) + { + return (_name == function.Name); + } + + public static bool Equals(Identifier a, Identifier b) + { + if (a == b) + return true; + + if (a != null && b != null) + return a.Equals(b); + + return false; + } + + public override int GetHashCode() + { + return _name.GetHashCode(); + } + + public override string ToString() + { + return _name; + } + + public static bool operator ==(Identifier a, Identifier b) + { + return Identifier.Equals(a, b); + } + + public static bool operator !=(Identifier a, Identifier b) + { + return !Identifier.Equals(a, b); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JavaScriptArray.cs b/Src/Newtonsoft.Json/JavaScriptArray.cs new file mode 100644 index 00000000..6456cdd7 --- /dev/null +++ b/Src/Newtonsoft.Json/JavaScriptArray.cs @@ -0,0 +1,64 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json +{ + /// + /// Represents a JavaScript array. + /// + public class JavaScriptArray : List + { + /// + /// Initializes a new instance of the class. + /// + public JavaScriptArray() + { + } + + /// + /// Initializes a new instance of the class that + /// contains elements copied from the specified collection. + /// + /// The collection whose elements are copied to the new array. + public JavaScriptArray(IEnumerable collection) + : base(collection) + { + } + + /// + /// Initializes a new instance of the class that + /// is empty and has the specified initial capacity. + /// + /// The number of elements that the new array can initially store. + public JavaScriptArray(int capacity) + : base(capacity) + { + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JavaScriptConstructor.cs b/Src/Newtonsoft.Json/JavaScriptConstructor.cs new file mode 100644 index 00000000..dd5b2b43 --- /dev/null +++ b/Src/Newtonsoft.Json/JavaScriptConstructor.cs @@ -0,0 +1,81 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json +{ + /// + /// Represents a JavaScript constructor. + /// + public class JavaScriptConstructor + { + private string _name; + private JavaScriptParameters _parameters; + + public JavaScriptParameters Parameters + { + get { return _parameters; } + } + + public string Name + { + get { return _name; } + } + + public JavaScriptConstructor(string name, JavaScriptParameters parameters) + { + if (name == null) + throw new ArgumentNullException("name"); + + if (name.Length == 0) + throw new ArgumentException("Constructor name cannot be empty.", "name"); + + _name = name; + _parameters = parameters ?? JavaScriptParameters.Empty; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + + sb.Append("new "); + sb.Append(_name); + sb.Append("("); + if (_parameters != null) + { + for (int i = 0; i < _parameters.Count; i++) + { + sb.Append(_parameters[i]); + } + } + sb.Append(")"); + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JavaScriptConvert.cs b/Src/Newtonsoft.Json/JavaScriptConvert.cs new file mode 100644 index 00000000..ea1f7df2 --- /dev/null +++ b/Src/Newtonsoft.Json/JavaScriptConvert.cs @@ -0,0 +1,448 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Web.UI.WebControls; +using System.Collections; +using System.IO; +using System.Globalization; +using System.Runtime.Serialization; +using System.Reflection; +using System.Data.SqlTypes; +using Newtonsoft.Json.Utilities; +using System.Xml; +using Newtonsoft.Json.Converters; + +namespace Newtonsoft.Json +{ + /// + /// Provides methods for converting between common language runtime types and JavaScript types. + /// + public static class JavaScriptConvert + { + /// + /// Represents JavaScript's boolean value true as a string. This field is read-only. + /// + public static readonly string True; + + /// + /// Represents JavaScript's boolean value false as a string. This field is read-only. + /// + public static readonly string False; + + /// + /// Represents JavaScript's null as a string. This field is read-only. + /// + public static readonly string Null; + + /// + /// Represents JavaScript's undefined as a string. This field is read-only. + /// + public static readonly string Undefined; + + internal static long InitialJavaScriptDateTicks; + internal static DateTime MinimumJavaScriptDate; + + static JavaScriptConvert() + { + True = "true"; + False = "false"; + Null = "null"; + Undefined = "undefined"; + + InitialJavaScriptDateTicks = (new DateTime(1970, 1, 1)).Ticks; + MinimumJavaScriptDate = new DateTime(100, 1, 1); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(DateTime value) + { + long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value); + + return "new Date(" + javaScriptTicks + ")"; + } + + internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime) + { + if (dateTime < MinimumJavaScriptDate) + dateTime = MinimumJavaScriptDate; + + long javaScriptTicks = (dateTime.Ticks - InitialJavaScriptDateTicks) / (long)10000; + + return javaScriptTicks; + } + + internal static DateTime ConvertJavaScriptTicksToDateTime(long javaScriptTicks) + { + DateTime dateTime = new DateTime((javaScriptTicks * 10000) + InitialJavaScriptDateTicks); + + return dateTime; + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(bool value) + { + return (value) ? True : False; + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(char value) + { + return ToString(char.ToString(value)); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(Enum value) + { + return value.ToString(); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(int value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(short value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(ushort value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(uint value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(long value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(ulong value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(float value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(double value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(byte value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(sbyte value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(decimal value) + { + return value.ToString(null, CultureInfo.InvariantCulture); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(Guid value) + { + return '"' + value.ToString("D", CultureInfo.InvariantCulture) + '"'; + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(string value) + { + return ToString(value, '"'); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// The string delimiter character. + /// A Json string representation of the . + public static string ToString(string value, char delimter) + { + return JavaScriptUtils.ToEscapedJavaScriptString(value, delimter, true); + } + + /// + /// Converts the to it's JavaScript string representation. + /// + /// The value to convert. + /// A Json string representation of the . + public static string ToString(object value) + { + if (value == null) + { + return Null; + } + else if (value is IConvertible) + { + IConvertible convertible = value as IConvertible; + + switch (convertible.GetTypeCode()) + { + case TypeCode.String: + return ToString((string)convertible); + case TypeCode.Char: + return ToString((char)convertible); + case TypeCode.Boolean: + return ToString((bool)convertible); + case TypeCode.SByte: + return ToString((sbyte)convertible); + case TypeCode.Int16: + return ToString((short)convertible); + case TypeCode.UInt16: + return ToString((ushort)convertible); + case TypeCode.Int32: + return ToString((int)convertible); + case TypeCode.Byte: + return ToString((byte)convertible); + case TypeCode.UInt32: + return ToString((uint)convertible); + case TypeCode.Int64: + return ToString((long)convertible); + case TypeCode.UInt64: + return ToString((ulong)convertible); + case TypeCode.Single: + return ToString((float)convertible); + case TypeCode.Double: + return ToString((double)convertible); + case TypeCode.DateTime: + return ToString((DateTime)convertible); + case TypeCode.Decimal: + return ToString((decimal)convertible); + } + } + + throw new ArgumentException(string.Format("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.", value.GetType())); + } + + /// + /// Serializes the specified object to a Json object. + /// + /// The object to serialize. + /// A Json string representation of the object. + public static string SerializeObject(object value) + { + return SerializeObject(value, null); + } + + public static string SerializeObject(object value, params JsonConverter[] converters) + { + StringWriter sw = new StringWriter(CultureInfo.InvariantCulture); + JsonSerializer jsonSerializer = new JsonSerializer(); + + if (!CollectionUtils.IsNullOrEmpty(converters)) + { + for (int i = 0; i < converters.Length; i++) + { + jsonSerializer.Converters.Add(converters[i]); + } + } + + using (JsonWriter jsonWriter = new JsonWriter(sw)) + { + //jsonWriter.Formatting = Formatting.Indented; + jsonSerializer.Serialize(jsonWriter, value); + } + + return sw.ToString(); + } + + /// + /// Deserializes the specified object to a Json object. + /// + /// The object to deserialize. + /// The deserialized object from the Json string. + public static object DeserializeObject(string value) + { + return DeserializeObject(value, null, null); + } + + /// + /// Deserializes the specified object to a Json object. + /// + /// The object to deserialize. + /// The of object being deserialized. + /// The deserialized object from the Json string. + public static object DeserializeObject(string value, Type type) + { + return DeserializeObject(value, type, null); + } + + /// + /// Deserializes the specified object to a Json object. + /// + /// The type of the object to deserialize. + /// The object to deserialize. + /// The deserialized object from the Json string. + public static T DeserializeObject(string value) + { + return DeserializeObject(value, null); + } + + /// + /// Deserializes the specified object to a Json object. + /// + /// The type of the object to deserialize. + /// The object to deserialize. + /// Converters to use while deserializing. + /// The deserialized object from the Json string. + public static T DeserializeObject(string value, params JsonConverter[] converters) + { + return (T)DeserializeObject(value, typeof(T), converters); + } + + public static object DeserializeObject(string value, Type type, params JsonConverter[] converters) + { + StringReader sr = new StringReader(value); + JsonSerializer jsonSerializer = new JsonSerializer(); + + if (!CollectionUtils.IsNullOrEmpty(converters)) + { + for (int i = 0; i < converters.Length; i++) + { + jsonSerializer.Converters.Add(converters[i]); + } + } + + object deserializedValue; + + using (JsonReader jsonReader = new JsonReader(sr)) + { + deserializedValue = jsonSerializer.Deserialize(jsonReader, type); + } + + return deserializedValue; + } + + public static string SerializeXmlNode(XmlNode node) + { + XmlNodeConverter converter = new XmlNodeConverter(); + + return SerializeObject(node, converter); + } + + public static XmlNode DeerializeXmlNode(string value) + { + XmlNodeConverter converter = new XmlNodeConverter(); + + return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), converter); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JavaScriptObject.cs b/Src/Newtonsoft.Json/JavaScriptObject.cs new file mode 100644 index 00000000..b1625bae --- /dev/null +++ b/Src/Newtonsoft.Json/JavaScriptObject.cs @@ -0,0 +1,55 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json +{ + /// + /// Represents a JavaScript object. + /// + public class JavaScriptObject : Dictionary + { + /// + /// Initializes a new instance of the class. + /// + public JavaScriptObject() + : base(EqualityComparer.Default) + { + } + + /// + /// Initializes a new instance of the class that + /// contains values copied from the specified . + /// + /// The whose elements are copied to the new object. + public JavaScriptObject(JavaScriptObject javaScriptObject) + : base(javaScriptObject, EqualityComparer.Default) + { + } + } +} diff --git a/Src/Newtonsoft.Json/JavaScriptParameters.cs b/Src/Newtonsoft.Json/JavaScriptParameters.cs new file mode 100644 index 00000000..ba0a2cd3 --- /dev/null +++ b/Src/Newtonsoft.Json/JavaScriptParameters.cs @@ -0,0 +1,42 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections.ObjectModel; + +namespace Newtonsoft.Json +{ + public class JavaScriptParameters : ReadOnlyCollection + { + public static readonly JavaScriptParameters Empty = new JavaScriptParameters(new List()); + + public JavaScriptParameters(IList list) + : base(list) + { + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonConverter.cs b/Src/Newtonsoft.Json/JsonConverter.cs new file mode 100644 index 00000000..bff625b1 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonConverter.cs @@ -0,0 +1,48 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json +{ + public abstract class JsonConverter + { + public virtual void WriteJson(JsonWriter writer, object value) + { + JsonSerializer serializer = new JsonSerializer(); + + serializer.Serialize(writer, value); + } + + public virtual object ReadJson(JsonReader reader, Type objectType) + { + throw new NotImplementedException(string.Format("{0} has not overriden FromJson method.", GetType().Name)); + } + + public abstract bool CanConvert(Type objectType); + } +} diff --git a/Src/Newtonsoft.Json/JsonConverterCollection.cs b/Src/Newtonsoft.Json/JsonConverterCollection.cs new file mode 100644 index 00000000..b19ab761 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonConverterCollection.cs @@ -0,0 +1,36 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections.ObjectModel; + +namespace Newtonsoft.Json +{ + public class JsonConverterCollection : Collection + { + } +} diff --git a/Src/Newtonsoft.Json/JsonHandler.cs b/Src/Newtonsoft.Json/JsonHandler.cs new file mode 100644 index 00000000..ca2a93f7 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonHandler.cs @@ -0,0 +1,63 @@ +using System; +using System.Web; +using System.Web.Caching; +using System.Xml; +using System.Text; +using System.Security.Principal; + +namespace Newtonsoft.Json +{ + public abstract class JsonHandler : HandlerBase, IHttpHandler + { + public event EventHandler Error; + + protected abstract void WriteResult(JsonWriter writer); + + public static void JsonResponse(HttpResponse response, Action writeAction) + { + response.ClearHeaders(); + response.ClearContent(); + + JsonWriter writer = new JsonWriter(response.Output); + + writeAction(writer); + + writer.Flush(); + } + + protected virtual void OnError(EventArgs e) + { + if (Error != null) + { + Error(this, e); + } + } + + void IHttpHandler.ProcessRequest(HttpContext context) + { + if (context == null) + throw new ArgumentNullException("context"); + + Context = context; + + try + { + JsonHandler.JsonResponse(context.Response, new Action(WriteResult)); + } + catch (Exception exception) + { + context.AddError(exception); + OnError(EventArgs.Empty); + if (context.Error != null) + { + throw new HttpUnhandledException("blah", exception); + } + } + } + + bool IHttpHandler.IsReusable + { + get { return false; } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonIgnoreAttribute.cs b/Src/Newtonsoft.Json/JsonIgnoreAttribute.cs new file mode 100644 index 00000000..8262998c --- /dev/null +++ b/Src/Newtonsoft.Json/JsonIgnoreAttribute.cs @@ -0,0 +1,36 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] + public sealed class JsonIgnoreAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonPropertyAttribute.cs b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs new file mode 100644 index 00000000..08f80948 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs @@ -0,0 +1,21 @@ +using System; + +namespace Newtonsoft.Json +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] + public sealed class JsonPropertyAttribute : Attribute + { + private string _propertyName; + + public string PropertyName + { + get { return _propertyName; } + set { _propertyName = value; } + } + + public JsonPropertyAttribute(string propertyName) + { + _propertyName = propertyName; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs new file mode 100644 index 00000000..197da206 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -0,0 +1,897 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Xml; +using System.Globalization; + +namespace Newtonsoft.Json +{ + /// + /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + /// + public class JsonReader : IDisposable + { + private enum State + { + Start, + Complete, + Property, + ObjectStart, + Object, + ArrayStart, + Array, + Closed, + PostValue, + Constructor, + ConstructorEnd, + Error, + Finished + } + + private TextReader _reader; + private char _currentChar; + + // current Token data + private JsonToken _token; + private object _value; + private Type _valueType; + private char _quoteChar; + private StringBuffer _buffer; + //private StringBuilder _testBuffer; + private State _currentState; + + private int _top; + private List _stack; + + /// + /// Gets the quotation mark character used to enclose the value of a string. + /// + public char QuoteChar + { + get { return _quoteChar; } + } + + /// + /// Gets the type of the current Json token. + /// + public JsonToken TokenType + { + get { return _token; } + } + + /// + /// Gets the text value of the current Json token. + /// + public object Value + { + get { return _value; } + } + + /// + /// Gets The Common Language Runtime (CLR) type for the current Json token. + /// + public Type ValueType + { + get { return _valueType; } + } + + /// + /// Initializes a new instance of the class with the specified . + /// + /// The TextReader containing the XML data to read. + public JsonReader(TextReader reader) + { + if (reader == null) + throw new ArgumentNullException("reader"); + + _reader = reader; + _buffer = new StringBuffer(4096); + //_testBuffer = new StringBuilder(); + _currentState = State.Start; + _stack = new List(); + _top = 0; + Push(JsonType.None); + } + + private void Push(JsonType value) + { + _stack.Add(value); + _top++; + } + + private JsonType Pop() + { + JsonType value = Peek(); + _stack.RemoveAt(_stack.Count - 1); + _top--; + + return value; + } + + private JsonType Peek() + { + return _stack[_top - 1]; + } + + private void ParseString(char quote) + { + bool stringTerminated = false; + + while (!stringTerminated && MoveNext()) + { + switch (_currentChar) + { + //case 0: + //case 0x0A: + //case 0x0D: + // throw new JsonReaderException("Unterminated string"); + case '\\': + if (MoveNext()) + { + switch (_currentChar) + { + case 'b': + _buffer.Append('\b'); + break; + case 't': + _buffer.Append('\t'); + break; + case 'n': + _buffer.Append('\n'); + break; + case 'f': + _buffer.Append('\f'); + break; + case 'r': + _buffer.Append('\r'); + break; + case 'u': + //_buffer.Append((char) Integer.parseInt(next(4), 16)); + break; + case 'x': + //_buffer.Append((char) Integer.parseInt(next(2), 16)); + break; + default: + _buffer.Append(_currentChar); + break; + } + } + else + { + throw new JsonReaderException("Unterminated string. Expected delimiter: " + quote); + } + break; + case '"': + case '\'': + if (_currentChar == quote) + stringTerminated = true; + else + goto default; + break; + default: + _buffer.Append(_currentChar); + break; + } + } + + if (!stringTerminated) + throw new JsonReaderException("Unterminated string. Expected delimiter: " + quote); + + ClearCurrentChar(); + _currentState = State.PostValue; + _token = JsonToken.String; + _value = _buffer.ToString(); + _buffer.Position = 0; + _valueType = typeof(string); + _quoteChar = quote; + } + + private bool MoveNext() + { + int value = _reader.Read(); + + if (value != -1) + { + _currentChar = (char)value; + //_testBuffer.Append(_currentChar); + return true; + } + else + { + return false; + } + } + + private bool HasNext() + { + return (_reader.Peek() != -1); + } + + private char PeekNext() + { + return (char)_reader.Peek(); + } + + private void ClearCurrentChar() + { + _currentChar = '\0'; + } + + private bool MoveTo(char value) + { + while (MoveNext()) + { + if (_currentChar == value) + return true; + } + return false; + } + + /// + /// Reads the next Json token from the stream. + /// + /// + public bool Read() + { + while (true) + { + if (_currentChar == '\0') + { + if (!MoveNext()) + return false; + } + + switch (_currentState) + { + case State.Start: + case State.Property: + case State.Array: + case State.ArrayStart: + return ParseValue(); + case State.Complete: + break; + case State.Object: + case State.ObjectStart: + return ParseObject(); + case State.PostValue: + // returns true if it hits + // end of object or array + if (ParsePostValue()) + return true; + break; + case State.Closed: + break; + case State.Error: + break; + default: + throw new JsonReaderException("Unexpected state: " + _currentState); + } + } + } + + private bool ParsePostValue() + { + do + { + switch (_currentChar) + { + case '}': + SetToken(JsonToken.EndObject); + ClearCurrentChar(); + return true; + case ']': + SetToken(JsonToken.EndArray); + ClearCurrentChar(); + return true; + case '/': + ParseComment(); + return true; + case ',': + // finished paring + SetStateBasedOnCurrent(); + ClearCurrentChar(); + return false; + default: + if (char.IsWhiteSpace(_currentChar)) + { + // eat whitespace + ClearCurrentChar(); + } + else + { + throw new JsonReaderException("After parsing a value an unexpected character was encoutered: " + _currentChar); + } + break; + } + } while (MoveNext()); + + return false; + } + + private bool ParseObject() + { + do + { + switch (_currentChar) + { + case '}': + SetToken(JsonToken.EndObject); + return true; + case '/': + ParseComment(); + return true; + case ',': + SetToken(JsonToken.Undefined); + return true; + default: + if (char.IsWhiteSpace(_currentChar)) + { + // eat + } + else + { + return ParseProperty(); + } + break; + } + } while (MoveNext()); + + return false; + } + + private bool ParseProperty() + { + if (ValidIdentifierChar(_currentChar)) + { + ParseUnquotedProperty(); + } + else if (_currentChar == '"' || _currentChar == '\'') + { + ParseQuotedProperty(_currentChar); + } + else + { + throw new JsonReaderException("Invalid property identifier character: " + _currentChar); + } + + // finished property. move to colon + if (_currentChar != ':') + { + MoveTo(':'); + } + + SetToken(JsonToken.PropertyName, _buffer.ToString()); + _buffer.Position = 0; + + return true; + } + + private void ParseQuotedProperty(char quoteChar) + { + // parse property name until quoted char is hit + while (MoveNext()) + { + if (_currentChar == quoteChar) + { + return; + } + else + { + _buffer.Append(_currentChar); + } + } + + throw new JsonReaderException("Unclosed quoted property. Expected: " + quoteChar); + } + + private bool ValidIdentifierChar(char value) + { + return (char.IsLetterOrDigit(_currentChar) || _currentChar == '_' || _currentChar == '$'); + } + + private void ParseUnquotedProperty() + { + // parse unquoted property name until whitespace or colon + _buffer.Append(_currentChar); + + while (MoveNext()) + { + if (char.IsWhiteSpace(_currentChar) || _currentChar == ':') + { + break; + } + else if (ValidIdentifierChar(_currentChar)) + { + _buffer.Append(_currentChar); + } + else + { + throw new JsonReaderException("Invalid JavaScript property identifier character: " + _currentChar); + } + } + } + + private void SetToken(JsonToken newToken) + { + SetToken(newToken, null); + } + + private void SetToken(JsonToken newToken, object value) + { + _token = newToken; + + switch (newToken) + { + case JsonToken.StartObject: + _currentState = State.ObjectStart; + Push(JsonType.Object); + ClearCurrentChar(); + break; + case JsonToken.StartArray: + _currentState = State.ArrayStart; + Push(JsonType.Array); + ClearCurrentChar(); + break; + case JsonToken.EndObject: + ValidateEnd(JsonToken.EndObject); + ClearCurrentChar(); + _currentState = State.PostValue; + break; + case JsonToken.EndArray: + ValidateEnd(JsonToken.EndArray); + ClearCurrentChar(); + _currentState = State.PostValue; + break; + case JsonToken.PropertyName: + _currentState = State.Property; + ClearCurrentChar(); + break; + case JsonToken.Undefined: + case JsonToken.Integer: + case JsonToken.Float: + case JsonToken.Boolean: + case JsonToken.Null: + case JsonToken.Constructor: + case JsonToken.Date: + _currentState = State.PostValue; + break; + } + + if (value != null) + { + _value = value; + _valueType = value.GetType(); + } + else + { + _value = null; + _valueType = null; + } + } + + private bool ParseValue() + { + do + { + switch (_currentChar) + { + case '"': + case '\'': + ParseString(_currentChar); + return true; + case 't': + ParseTrue(); + return true; + case 'f': + ParseFalse(); + return true; + case 'n': + if (HasNext()) + { + char next = PeekNext(); + + if (next == 'u') + ParseNull(); + else if (next == 'e') + ParseConstructor(); + else + throw new JsonReaderException("Unexpected character encountered while parsing value: " + _currentChar); + } + else + { + throw new JsonReaderException("Unexpected end"); + } + return true; + case '/': + ParseComment(); + return true; + case 'u': + ParseUndefined(); + return true; + case '{': + SetToken(JsonToken.StartObject); + return true; + case '[': + SetToken(JsonToken.StartArray); + return true; + case '}': + SetToken(JsonToken.EndObject); + return true; + case ']': + SetToken(JsonToken.EndArray); + return true; + case ',': + SetToken(JsonToken.Undefined); + //ClearCurrentChar(); + return true; + case ')': + if (_currentState == State.Constructor) + { + _currentState = State.ConstructorEnd; + return false; + } + else + { + throw new JsonReaderException("Unexpected character encountered while parsing value: " + _currentChar); + } + default: + if (char.IsWhiteSpace(_currentChar)) + { + // eat + } + else if (char.IsNumber(_currentChar) || _currentChar == '-' || _currentChar == '.') + { + ParseNumber(); + return true; + } + else + { + throw new JsonReaderException("Unexpected character encountered while parsing value: " + _currentChar); + } + break; + } + } while (MoveNext()); + + return false; + } + + private bool EatWhitespace(bool oneOrMore) + { + bool whitespace = false; + while (char.IsWhiteSpace(_currentChar)) + { + whitespace = true; + MoveNext(); + } + + return (!oneOrMore || whitespace); + } + + private void ParseConstructor() + { + if (MatchValue("new", true)) + { + if (EatWhitespace(true)) + { + while (char.IsLetter(_currentChar)) + { + _buffer.Append(_currentChar); + MoveNext(); + } + + string constructorName = _buffer.ToString(); + _buffer.Position = 0; + + List parameters = new List(); + + EatWhitespace(false); + + if (_currentChar == '(' && MoveNext()) + { + _currentState = State.Constructor; + + while (ParseValue()) + { + parameters.Add(_value); + _currentState = State.Constructor; + } + + if (string.CompareOrdinal(constructorName, "Date") == 0) + { + long javaScriptTicks = Convert.ToInt64(parameters[0]); + + DateTime date = JavaScriptConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks); + + SetToken(JsonToken.Date, date); + } + else + { + JavaScriptConstructor constructor = new JavaScriptConstructor(constructorName, new JavaScriptParameters(parameters)); + + if (_currentState == State.ConstructorEnd) + { + SetToken(JsonToken.Constructor, constructor); + } + } + + // move past ')' + MoveNext(); + } + } + } + } + + private void ParseNumber() + { + // parse until seperator character or end + bool end = false; + do + { + if (CurrentIsSeperator()) + end = true; + else + _buffer.Append(_currentChar); + + } while (!end && MoveNext()); + + string number = _buffer.ToString(); + object numberValue; + JsonToken numberType; + + if (number.IndexOf('.') == -1) + { + numberValue = Convert.ToInt64(_buffer.ToString(), CultureInfo.InvariantCulture); + numberType = JsonToken.Integer; + } + else + { + numberValue = Convert.ToDouble(_buffer.ToString(), CultureInfo.InvariantCulture); + numberType = JsonToken.Float; + } + + _buffer.Position = 0; + + SetToken(numberType, numberValue); + } + + private void ValidateEnd(JsonToken endToken) + { + JsonType currentObject = Pop(); + + if (GetTypeForCloseToken(endToken) != currentObject) + throw new JsonReaderException(string.Format("JsonToken {0} is not valid for closing JsonType {1}.", endToken, currentObject)); + } + + private void SetStateBasedOnCurrent() + { + JsonType currentObject = Peek(); + + switch (currentObject) + { + case JsonType.Object: + _currentState = State.Object; + break; + case JsonType.Array: + _currentState = State.Array; + break; + case JsonType.None: + _currentState = State.Finished; + break; + default: + throw new JsonReaderException("While setting the reader state back to current object an unexpected JsonType was encountered: " + currentObject); + } + } + + private JsonType GetTypeForCloseToken(JsonToken token) + { + switch (token) + { + case JsonToken.EndObject: + return JsonType.Object; + case JsonToken.EndArray: + return JsonType.Array; + default: + throw new JsonReaderException("Not a valid close JsonToken: " + token); + } + } + + private void ParseComment() + { + // should have already parsed / character before reaching this method + + MoveNext(); + + if (_currentChar == '*') + { + while (MoveNext()) + { + if (_currentChar == '*') + { + if (MoveNext()) + { + if (_currentChar == '/') + { + break; + } + else + { + _buffer.Append('*'); + _buffer.Append(_currentChar); + } + } + } + else + { + _buffer.Append(_currentChar); + } + } + } + else + { + throw new JsonReaderException("Error parsing comment. Expected: *"); + } + + SetToken(JsonToken.Comment, _buffer.ToString()); + + _buffer.Position = 0; + + ClearCurrentChar(); + } + + private bool MatchValue(string value) + { + int i = 0; + do + { + if (_currentChar != value[i]) + { + break; + } + i++; + } + while (i < value.Length && MoveNext()); + + return (i == value.Length); + } + + private bool MatchValue(string value, bool noTrailingNonSeperatorCharacters) + { + // will match value and then move to the next character, checking that it is a seperator character + bool match = MatchValue(value); + + if (!noTrailingNonSeperatorCharacters) + return match; + else + return (match && (!MoveNext() || CurrentIsSeperator())); + } + + private bool CurrentIsSeperator() + { + switch (_currentChar) + { + case '}': + case ']': + case ',': + return true; + case '/': + // check next character to see if start of a comment + return (HasNext() && PeekNext() == '*'); + case ')': + if (_currentState == State.Constructor) + return true; + break; + default: + if (char.IsWhiteSpace(_currentChar)) + return true; + break; + } + + return false; + } + + private void ParseTrue() + { + // check characters equal 'true' + // and that it is followed by either a seperator character + // or the text ends + if (MatchValue(JavaScriptConvert.True, true)) + { + SetToken(JsonToken.Boolean, true); + } + else + { + throw new JsonReaderException("Error parsing boolean value."); + } + } + + private void ParseNull() + { + if (MatchValue(JavaScriptConvert.Null, true)) + { + SetToken(JsonToken.Null); + } + else + { + throw new JsonReaderException("Error parsing null value."); + } + } + + private void ParseUndefined() + { + if (MatchValue(JavaScriptConvert.Undefined, true)) + { + SetToken(JsonToken.Undefined); + } + else + { + throw new JsonReaderException("Error parsing undefined value."); + } + } + + private void ParseFalse() + { + if (MatchValue(JavaScriptConvert.False, true)) + { + SetToken(JsonToken.Boolean, false); + } + else + { + throw new JsonReaderException("Error parsing boolean value."); + } + } + + void IDisposable.Dispose() + { + Dispose(true); + } + + private void Dispose(bool disposing) + { + if (_currentState != State.Closed && disposing) + Close(); + } + + /// + /// Changes the to Closed. + /// + public void Close() + { + _currentState = State.Closed; + _token = JsonToken.None; + _value = null; + _valueType = null; + + if (_reader != null) + _reader.Close(); + + if (_buffer != null) + _buffer.Clear(); + } + } +} diff --git a/Src/Newtonsoft.Json/JsonReaderException.cs b/Src/Newtonsoft.Json/JsonReaderException.cs new file mode 100644 index 00000000..9940c670 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonReaderException.cs @@ -0,0 +1,65 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json +{ + /// + /// The exception thrown when an error occurs while reading Json text. + /// + public class JsonReaderException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public JsonReaderException() + { + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public JsonReaderException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class + /// with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + public JsonReaderException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/Src/Newtonsoft.Json/JsonSerializationException.cs b/Src/Newtonsoft.Json/JsonSerializationException.cs new file mode 100644 index 00000000..bec26350 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonSerializationException.cs @@ -0,0 +1,65 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json +{ + /// + /// The exception thrown when an error occurs during Json serialization or deserialization. + /// + public class JsonSerializationException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public JsonSerializationException() + { + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public JsonSerializationException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class + /// with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + public JsonSerializationException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs new file mode 100644 index 00000000..43dabb3d --- /dev/null +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -0,0 +1,649 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Collections; +using System.Reflection; +using System.ComponentModel; +using Newtonsoft.Json.Utilities; +using System.Globalization; + +namespace Newtonsoft.Json +{ + /// + /// Specifies reference loop handling options for the . + /// + public enum ReferenceLoopHandling + { + /// + /// Throw a when a loop is encountered. + /// + Error = 0, + /// + /// Ignore loop references and do not serialize. + /// + Ignore = 1, + /// + /// Serialize loop references. + /// + Serialize = 2 + } + + /// + /// Serializes and deserializes objects into and from the Json format. + /// The enables you to control how objects are encoded into Json. + /// + public class JsonSerializer + { + private ReferenceLoopHandling _referenceLoopHandling; + private int _level; + private JsonConverterCollection _converters; + private Dictionary _typeMemberMappings; + + /// + /// Get or set how reference loops (e.g. a class referencing itself) is handled. + /// + public ReferenceLoopHandling ReferenceLoopHandling + { + get { return _referenceLoopHandling; } + set + { + if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize) + { + throw new ArgumentOutOfRangeException("value"); + } + _referenceLoopHandling = value; + } + } + + public JsonConverterCollection Converters + { + get + { + if (_converters == null) + _converters = new JsonConverterCollection(); + + return _converters; + } + } + + /// + /// Initializes a new instance of the class. + /// + public JsonSerializer() + { + _referenceLoopHandling = ReferenceLoopHandling.Error; + } + + #region Deserialize + /// + /// Deserializes the Json structure contained by the specified . + /// + /// The that contains the Json structure to deserialize. + /// The being deserialized. + public object Deserialize(JsonReader reader) + { + return Deserialize(reader, null); + } + + /// + /// Deserializes the Json structure contained by the specified + /// into an instance of the specified type. + /// + /// The type of object to create. + /// The of object being deserialized. + /// The instance of being deserialized. + public object Deserialize(JsonReader reader, Type objectType) + { + if (reader == null) + throw new ArgumentNullException("reader"); + + if (!reader.Read()) + return null; + + return GetObject(reader, objectType); + } + + private JavaScriptArray PopulateJavaScriptArray(JsonReader reader) + { + JavaScriptArray jsArray = new JavaScriptArray(); + + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonToken.EndArray: + return jsArray; + case JsonToken.Comment: + break; + default: + object value = GetObject(reader, null); + + jsArray.Add(value); + break; + } + } + + throw new JsonSerializationException("Unexpected end while deserializing array."); + } + + private JavaScriptObject PopulateJavaScriptObject(JsonReader reader) + { + JavaScriptObject jsObject = new JavaScriptObject(); + + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonToken.PropertyName: + string memberName = reader.Value.ToString(); + + // move to the value token. skip comments + do + { + if (!reader.Read()) + throw new JsonSerializationException("Unexpected end while deserializing object."); + } while (reader.TokenType == JsonToken.Comment); + + object value = GetObject(reader, null); + + jsObject[memberName] = value; + break; + case JsonToken.EndObject: + return jsObject; + case JsonToken.Comment: + break; + default: + throw new JsonSerializationException("Unexpected token while deserializing object: " + reader.TokenType); + } + } + + throw new JsonSerializationException("Unexpected end while deserializing object."); + } + + private object GetObject(JsonReader reader, Type objectType) + { + _level++; + + object value; + JsonConverter converter; + + if (HasMatchingConverter(objectType, out converter)) + { + return converter.ReadJson(reader, objectType); + } + else + { + switch (reader.TokenType) + { + // populate a typed object or generic dictionary/array + // depending upon whether an objectType was supplied + case JsonToken.StartObject: + value = (objectType != null) ? PopulateObject(reader, objectType) : PopulateJavaScriptObject(reader); + break; + case JsonToken.StartArray: + value = (objectType != null) ? PopulateList(reader, objectType) : PopulateJavaScriptArray(reader); + break; + case JsonToken.Integer: + case JsonToken.Float: + case JsonToken.String: + case JsonToken.Boolean: + case JsonToken.Date: + value = EnsureType(reader.Value, objectType); + break; + case JsonToken.Constructor: + value = reader.Value.ToString(); + break; + case JsonToken.Null: + case JsonToken.Undefined: + value = null; + break; + default: + throw new JsonSerializationException("Unexpected token whil deserializing object: " + reader.TokenType); + } + } + + _level--; + + return value; + } + + private object EnsureType(object value, Type targetType) + { + // do something about null value when the targetType is a valuetype? + if (value == null) + return null; + + if (targetType == null) + return value; + + Type valueType = value.GetType(); + + // type of value and type of target don't match + // attempt to convert value's type to target's type + if (valueType != targetType) + { + TypeConverter targetConverter = TypeDescriptor.GetConverter(targetType); + + if (!targetConverter.CanConvertFrom(valueType)) + { + if (targetConverter.CanConvertFrom(typeof(string))) + { + string valueString = TypeDescriptor.GetConverter(value).ConvertToInvariantString(value); + + return targetConverter.ConvertFromInvariantString(valueString); + } + + if (!targetType.IsAssignableFrom(valueType)) + throw new InvalidOperationException(string.Format("Cannot convert object of type '{0}' to type '{1}'", value.GetType(), targetType)); + + return value; + } + + return targetConverter.ConvertFrom(null, CultureInfo.InvariantCulture, value); + } + else + { + return value; + } + } + + private MemberMappingCollection GetMemberMappings(Type objectType) + { + if (_typeMemberMappings == null) + _typeMemberMappings = new Dictionary(); + + MemberMappingCollection memberMappings; + + if (_typeMemberMappings.TryGetValue(objectType, out memberMappings)) + return memberMappings; + + memberMappings = CreateMemberMappings(objectType); + _typeMemberMappings[objectType] = memberMappings; + + return memberMappings; + } + + private MemberMappingCollection CreateMemberMappings(Type objectType) + { + List members = ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.Instance); + MemberMappingCollection memberMappings = new MemberMappingCollection(); + + foreach (MemberInfo member in members) + { + string mappedName; + + JsonPropertyAttribute propertyAttribute = ReflectionUtils.GetAttribute(member, true); + if (propertyAttribute != null) + mappedName = propertyAttribute.PropertyName; + else + mappedName = member.Name; + + bool ignored = member.IsDefined(typeof (JsonIgnoreAttribute), true); + bool readable = ReflectionUtils.CanReadMemberValue(member); + bool writable = ReflectionUtils.CanSetMemberValue(member); + MemberMapping memberMapping = new MemberMapping(mappedName, member, ignored, readable, writable); + + memberMappings.AddMapping(memberMapping); + } + + return memberMappings; + } + + private void SetObjectMember(JsonReader reader, object target, Type targetType, string memberName) + { + if (!reader.Read()) + throw new JsonSerializationException(string.Format("Unexpected end when setting {0}'s value.", memberName)); + + MemberMappingCollection memberMappings = GetMemberMappings(targetType); + Type memberType; + object value; + + // test if a member with memberName exists on the type + // otherwise test if target is a dictionary and assign value with the key if it is + if (memberMappings.Contains(memberName)) + { + MemberMapping memberMapping = memberMappings[memberName]; + + if (memberMapping.Ignored) + return; + + // ignore member if it is readonly + if (!memberMapping.Writable) + return; + + // get the member's underlying type + memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member); + + value = GetObject(reader, memberType); + + ReflectionUtils.SetMemberValue(memberMapping.Member, target, value); + } + else if (typeof(IDictionary).IsAssignableFrom(targetType)) + { + // attempt to get the IDictionary's type + memberType = ReflectionUtils.GetDictionaryValueType(target.GetType()); + + value = GetObject(reader, memberType); + + ((IDictionary)target).Add(memberName, value); + } + else + { + throw new JsonSerializationException(string.Format("Could not find member '{0}' on object of type '{1}'", memberName, targetType.GetType().Name)); + } + } + + private object PopulateList(JsonReader reader, Type objectType) + { + Type elementType = ReflectionUtils.GetListItemType(objectType); + + IList populatedList = CollectionUtils.CreateAndPopulateList(objectType, delegate(IList list) + { + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonToken.EndArray: + return; + case JsonToken.Comment: + break; + default: + object value = GetObject(reader, elementType); + + list.Add(value); + break; + } + } + + throw new JsonSerializationException("Unexpected end when deserializing array."); + }); + + return populatedList; + } + + private object PopulateObject(JsonReader reader, Type objectType) + { + object newObject = Activator.CreateInstance(objectType); + + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonToken.PropertyName: + string memberName = reader.Value.ToString(); + + SetObjectMember(reader, newObject, objectType, memberName); + break; + case JsonToken.EndObject: + return newObject; + default: + throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType); + } + } + + throw new JsonSerializationException("Unexpected end when deserializing object."); + } + #endregion + + #region Serialize + /// + /// Serializes the specified and writes the Json structure + /// to a Stream using the specified . + /// + /// The used to write the Json structure. + /// The to serialize. + public void Serialize(TextWriter textWriter, object value) + { + Serialize(new JsonWriter(textWriter), value); + } + + /// + /// Serializes the specified and writes the Json structure + /// to a Stream using the specified . + /// + /// The used to write the Json structure. + /// The to serialize. + public void Serialize(JsonWriter jsonWriter, object value) + { + if (jsonWriter == null) + throw new ArgumentNullException("jsonWriter"); + + if (value == null) + throw new ArgumentNullException("value"); + + SerializeValue(jsonWriter, value); + } + + + private void SerializeValue(JsonWriter writer, object value) + { + JsonConverter converter; + + if (value == null) + { + writer.WriteNull(); + } + else if (HasMatchingConverter(value.GetType(), out converter)) + { + converter.WriteJson(writer, value); + } + else if (value is IConvertible) + { + IConvertible convertible = value as IConvertible; + + switch (convertible.GetTypeCode()) + { + case TypeCode.String: + writer.WriteValue((string)convertible); + break; + case TypeCode.Char: + writer.WriteValue((char)convertible); + break; + case TypeCode.Boolean: + writer.WriteValue((bool)convertible); + break; + case TypeCode.SByte: + writer.WriteValue((sbyte)convertible); + break; + case TypeCode.Int16: + writer.WriteValue((short)convertible); + break; + case TypeCode.UInt16: + writer.WriteValue((ushort)convertible); + break; + case TypeCode.Int32: + writer.WriteValue((int)convertible); + break; + case TypeCode.Byte: + writer.WriteValue((byte)convertible); + break; + case TypeCode.UInt32: + writer.WriteValue((uint)convertible); + break; + case TypeCode.Int64: + writer.WriteValue((long)convertible); + break; + case TypeCode.UInt64: + writer.WriteValue((ulong)convertible); + break; + case TypeCode.Single: + writer.WriteValue((float)convertible); + break; + case TypeCode.Double: + writer.WriteValue((double)convertible); + break; + case TypeCode.DateTime: + writer.WriteValue((DateTime)convertible); + break; + case TypeCode.Decimal: + writer.WriteValue((decimal)convertible); + break; + default: + SerializeObject(writer, value); + break; + } + } + else if (value is IList) + { + SerializeList(writer, (IList)value); + } + else if (value is IDictionary) + { + SerializeDictionary(writer, (IDictionary)value); + } + else if (value is ICollection) + { + SerializeCollection(writer, (ICollection)value); + } + else if (value is Identifier) + { + writer.WriteRaw(value.ToString()); + } + else + { + SerializeObject(writer, value); + } + } + + private bool HasMatchingConverter(Type type, out JsonConverter matchingConverter) + { + if (_converters != null) + { + for (int i = 0; i < _converters.Count; i++) + { + JsonConverter converter = _converters[i]; + + if (converter.CanConvert(type)) + { + matchingConverter = converter; + return true; + } + } + } + + matchingConverter = null; + return false; + } + + private void WriteMemberInfoProperty(JsonWriter writer, object value, MemberInfo member, string propertyName) + { + if (!ReflectionUtils.IsIndexedProperty(member)) + { + object memberValue = ReflectionUtils.GetMemberValue(member, value); + + if (writer.SerializeStack.IndexOf(memberValue) != -1) + { + switch (_referenceLoopHandling) + { + case ReferenceLoopHandling.Error: + throw new JsonSerializationException("Self referencing loop"); + case ReferenceLoopHandling.Ignore: + // return from method + return; + case ReferenceLoopHandling.Serialize: + // continue + break; + default: + throw new InvalidOperationException(string.Format("Unexpected ReferenceLoopHandling value: '{0}'", _referenceLoopHandling)); + } + } + + writer.WritePropertyName(propertyName ?? member.Name); + SerializeValue(writer, memberValue); + } + } + + private void SerializeObject(JsonWriter writer, object value) + { + Type objectType = value.GetType(); + + TypeConverter converter = TypeDescriptor.GetConverter(objectType); + + // use the objectType's TypeConverter if it has one and can convert to a string + if (converter != null && !(converter is ComponentConverter) && converter.GetType() != typeof(TypeConverter)) + { + if (converter.CanConvertTo(typeof(string))) + { + writer.WriteValue(converter.ConvertToInvariantString(value)); + return; + } + } + + writer.SerializeStack.Add(value); + + writer.WriteStartObject(); + + MemberMappingCollection memberMappings = GetMemberMappings(objectType); + + foreach (MemberMapping memberMapping in memberMappings) + { + if (!memberMapping.Ignored && memberMapping.Readable) + WriteMemberInfoProperty(writer, value, memberMapping.Member, memberMapping.MappingName); + } + + writer.WriteEndObject(); + + writer.SerializeStack.Remove(value); + } + + private void SerializeCollection(JsonWriter writer, ICollection values) + { + object[] collectionValues = new object[values.Count]; + values.CopyTo(collectionValues, 0); + + SerializeList(writer, collectionValues); + } + + private void SerializeList(JsonWriter writer, IList values) + { + writer.WriteStartArray(); + + for (int i = 0; i < values.Count; i++) + { + SerializeValue(writer, values[i]); + } + + writer.WriteEndArray(); + } + + private void SerializeDictionary(JsonWriter writer, IDictionary values) + { + writer.WriteStartObject(); + + foreach (DictionaryEntry entry in values) + { + writer.WritePropertyName(entry.Key.ToString()); + SerializeValue(writer, entry.Value); + } + + writer.WriteEndObject(); + } + #endregion + } +} diff --git a/Src/Newtonsoft.Json/JsonToken.cs b/Src/Newtonsoft.Json/JsonToken.cs new file mode 100644 index 00000000..e64d8758 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonToken.cs @@ -0,0 +1,98 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json +{ + /// + /// Specifies the type of Json token. + /// + public enum JsonToken + { + /// + /// This is returned by the if a method has not been called. + /// + None, + /// + /// An object start token. + /// + StartObject, + /// + /// An array start token. + /// + StartArray, + /// + /// An object property name. + /// + PropertyName, + /// + /// A comment. + /// + Comment, + /// + /// An interger. + /// + Integer, + /// + /// A float. + /// + Float, + /// + /// A string. + /// + String, + /// + /// A boolean. + /// + Boolean, + /// + /// A null token. + /// + Null, + /// + /// An undefined token. + /// + Undefined, + /// + /// An object end token. + /// + EndObject, + /// + /// An array end token. + /// + EndArray, + /// + /// A JavaScript object constructor. + /// + Constructor, + /// + /// A Date. + /// + Date + } +} diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs new file mode 100644 index 00000000..499aa721 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -0,0 +1,732 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Xml; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json +{ + internal enum JsonType + { + Object, + Array, + None + } + + /// + /// Specifies the state of the . + /// + public enum WriteState + { + /// + /// An exception has been thrown, which has left the in an invalid state. + /// You may call the method to put the in the Closed state. + /// Any other method calls results in an being thrown. + /// + Error, + /// + /// The method has been called. + /// + Closed, + /// + /// An object is being written. + /// + Object, + /// + /// A array is being written. + /// + Array, + /// + /// A property is being written. + /// + Property, + /// + /// A write method has not been called. + /// + Start + } + + /// + /// Specifies formatting options for the . + /// + public enum Formatting + { + /// + /// No special formatting is applied. This is the default. + /// + None, + /// + /// Causes child objects to be indented according to the and settings. + /// + Indented + } + + /// + /// Represents a writer that provides a fast, non-cached, forward-only way of generating Json data. + /// + public class JsonWriter : IDisposable + { + private enum State + { + Start, + Property, + ObjectStart, + Object, + ArrayStart, + Array, + Closed, + Error + } + + // array that gives a new state based on the current state an the token being written + private static readonly State[,] stateArray = { + // Start PropertyName ObjectStart Object ArrayStart Array Closed Error + // + /* None */{ State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error }, + /* StartObject */{ State.ObjectStart, State.ObjectStart, State.Error, State.Error, State.ObjectStart, State.ObjectStart, State.Error, State.Error }, + /* StartArray */{ State.ArrayStart, State.ArrayStart, State.Error, State.Error, State.ArrayStart, State.ArrayStart, State.Error, State.Error }, + /* StartProperty */{ State.Error, State.Error, State.Property, State.Property, State.Error, State.Error, State.Error, State.Error }, + /* Comment */{ State.Error, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Error, State.Error }, + /* Value */{ State.Error, State.Object, State.Error, State.Error, State.Array, State.Array, State.Error, State.Error }, + }; + + private int _top; + private List _stack; + private List _serializeStack; + private TextWriter _writer; + private Formatting _formatting; + private char _indentChar; + private int _indentation; + private char _quoteChar; + private bool _quoteName; + private State _currentState; + + internal List SerializeStack + { + get + { + if (_serializeStack == null) + _serializeStack = new List(); + + return _serializeStack; + } + } + + /// + /// Gets the state of the writer. + /// + public WriteState WriteState + { + get + { + switch (_currentState) + { + case State.Error: + return WriteState.Error; + case State.Closed: + return WriteState.Closed; + case State.Object: + case State.ObjectStart: + return WriteState.Object; + case State.Array: + case State.ArrayStart: + return WriteState.Array; + case State.Property: + return WriteState.Property; + case State.Start: + return WriteState.Start; + default: + throw new JsonWriterException("Invalid state: " + _currentState); + } + } + } + + /// + /// Indicates how the output is formatted. + /// + public Formatting Formatting + { + get { return _formatting; } + set { _formatting = value; } + } + + /// + /// Gets or sets how many IndentChars to write for each level in the hierarchy when is set to Formatting.Indented. + /// + public int Indentation + { + get { return _indentation; } + set + { + if (value < 0) + throw new ArgumentException("Indentation value must be greater than 0."); + + _indentation = value; + } + } + + /// + /// Gets or sets which character to use to quote attribute values. + /// + public char QuoteChar + { + get { return _quoteChar; } + set + { + if (value != '"' && value != '\'') + throw new ArgumentException(@"Invalid JavaScript string quote character. Valid quote characters are ' and ""."); + + _quoteChar = value; + } + } + + /// + /// Gets or sets which character to use for indenting when is set to Formatting.Indented. + /// + public char IndentChar + { + get { return _indentChar; } + set { _indentChar = value; } + } + + /// + /// Gets or sets a value indicating whether object names will be surrounded with quotes. + /// + public bool QuoteName + { + get { return _quoteName; } + set { _quoteName = value; } + } + + /// + /// Creates an instance of the JsonWriter class using the specified . + /// + /// The TextWriter to write to. + public JsonWriter(TextWriter textWriter) + { + if (textWriter == null) + throw new ArgumentNullException("textWriter"); + + _writer = textWriter; + _quoteChar = '"'; + _quoteName = true; + _indentChar = ' '; + _indentation = 2; + _formatting = Formatting.None; + _stack = new List(1); + _stack.Add(JsonType.None); + _currentState = State.Start; + } + + private void Push(JsonType value) + { + _top++; + if (_stack.Count <= _top) + _stack.Add(value); + else + _stack[_top] = value; + } + + private JsonType Pop() + { + JsonType value = Peek(); + _top--; + + return value; + } + + private JsonType Peek() + { + return _stack[_top]; + } + + /// + /// Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. + /// + public void Flush() + { + _writer.Flush(); + } + + /// + /// Closes this stream and the underlying stream. + /// + public void Close() + { + AutoCompleteAll(); + + _writer.Close(); + } + + /// + /// Writes the beginning of a Json object. + /// + public void WriteStartObject() + { + AutoComplete(JsonToken.StartObject); + + Push(JsonType.Object); + + _writer.Write("{"); + } + + /// + /// Writes the end of a Json object. + /// + public void WriteEndObject() + { + AutoCompleteClose(JsonToken.EndObject); + } + + /// + /// Writes the beginning of a Json array. + /// + public void WriteStartArray() + { + AutoComplete(JsonToken.StartArray); + Push(JsonType.Array); + _writer.Write("["); + } + + /// + /// Writes the end of an array. + /// + public void WriteEndArray() + { + AutoCompleteClose(JsonToken.EndArray); + } + + /// + /// Writes the property name of a name/value pair on a Json object. + /// + /// + public void WritePropertyName(string name) + { + //_objectStack.Push(new JsonObjectInfo(JsonType.Property)); + AutoComplete(JsonToken.PropertyName); + + if (_quoteName) + _writer.Write(_quoteChar); + + _writer.Write(name); + + if (_quoteName) + _writer.Write(_quoteChar); + + _writer.Write(':'); + } + + /// + /// Writes the end of the current Json object or array. + /// + public void WriteEnd() + { + WriteEnd(Peek()); + } + + private void WriteEnd(JsonType type) + { + switch (type) + { + case JsonType.Object: + WriteEndObject(); + break; + case JsonType.Array: + WriteEndArray(); + break; + default: + throw new JsonWriterException("Unexpected type when writing end: " + type); + } + } + + private void AutoCompleteAll() + { + while (_top > 0) + { + WriteEnd(); + } + } + + private JsonType GetTypeForCloseToken(JsonToken token) + { + switch (token) + { + case JsonToken.EndObject: + return JsonType.Object; + case JsonToken.EndArray: + return JsonType.Array; + default: + throw new JsonWriterException("No type for token: " + token); + } + } + + private JsonToken GetCloseTokenForType(JsonType type) + { + switch (type) + { + case JsonType.Object: + return JsonToken.EndObject; + case JsonType.Array: + return JsonToken.EndArray; + default: + throw new JsonWriterException("No close token for type: " + type); + } + } + + private void AutoCompleteClose(JsonToken tokenBeingClosed) + { + // write closing symbol and calculate new state + + int levelsToComplete = 0; + + for (int i = 0; i < _top; i++) + { + int currentLevel = _top - i; + + if (_stack[currentLevel] == GetTypeForCloseToken(tokenBeingClosed)) + { + levelsToComplete = i + 1; + break; + } + } + + if (levelsToComplete == 0) + throw new JsonWriterException("No token to close."); + + for (int i = 0; i < levelsToComplete; i++) + { + JsonToken token = GetCloseTokenForType(Pop()); + + if (_currentState != State.ObjectStart && _currentState != State.ArrayStart) + WriteIndent(); + + switch (token) + { + case JsonToken.EndObject: + _writer.Write("}"); + break; + case JsonToken.EndArray: + _writer.Write("]"); + break; + default: + throw new JsonWriterException("Invalid JsonToken: " + token); + } + } + + JsonType currentLevelType = Peek(); + + switch (currentLevelType) + { + case JsonType.Object: + _currentState = State.Object; + break; + case JsonType.Array: + _currentState = State.Array; + break; + case JsonType.None: + _currentState = State.Start; + break; + default: + throw new JsonWriterException("Unknown JsonType: " + currentLevelType); + } + } + + private void WriteIndent() + { + if (_formatting == Formatting.Indented) + { + _writer.Write(Environment.NewLine); + // for each level of object... + for (int i = 0; i < _top; i++) + { + // ...write the indent char the specified number of times + for (int j = 0; j < _indentation; j++) + { + _writer.Write(_indentChar); + } + } + } + } + + private void AutoComplete(JsonToken tokenBeingWritten) + { + int token; + + switch (tokenBeingWritten) + { + default: + token = (int)tokenBeingWritten; + break; + case JsonToken.Integer: + case JsonToken.Float: + case JsonToken.String: + case JsonToken.Boolean: + case JsonToken.Null: + case JsonToken.Undefined: + case JsonToken.Date: + // a value is being written + token = 5; + break; + } + + // gets new state based on the current state and what is being written + State newState = stateArray[token, (int)_currentState]; + + if (newState == State.Error) + throw new JsonWriterException(string.Format("Token {0} in state {1} would result in an invalid JavaScript object.", tokenBeingWritten.ToString(), _currentState.ToString())); + + if ((_currentState == State.Object || _currentState == State.Array) && tokenBeingWritten != JsonToken.Comment) + { + _writer.Write(','); + } + else if (_currentState == State.Property) + { + if (_formatting == Formatting.Indented) + _writer.Write(' '); + } + + if (tokenBeingWritten == JsonToken.PropertyName || + (WriteState == WriteState.Array)) + { + WriteIndent(); + } + + _currentState = newState; + } + + private void WriteValueInternal(string value, JsonToken token) + { + AutoComplete(token); + + _writer.Write(value); + } + + #region WriteValue methods + /// + /// Writes a null value. + /// + public void WriteNull() + { + WriteValueInternal(JavaScriptConvert.Null, JsonToken.Null); + } + + /// + /// Writes an undefined value. + /// + public void WriteUndefined() + { + WriteValueInternal(JavaScriptConvert.Undefined, JsonToken.Undefined); + } + + /// + /// Writes raw JavaScript manually. + /// + /// The raw JavaScript to write. + public void WriteRaw(string javaScript) + { + // hack. some 'raw' or 'other' token perhaps? + WriteValueInternal(javaScript, JsonToken.Undefined); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(string value) + { + WriteValueInternal(JavaScriptConvert.ToString(value, _quoteChar), JsonToken.String); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(int value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(uint value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(long value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(ulong value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(float value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Float); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(double value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Float); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(bool value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Boolean); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(short value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(ushort value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(char value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(byte value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(sbyte value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(decimal value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Float); + } + + /// + /// Writes a value. + /// + /// The value to write. + public void WriteValue(DateTime value) + { + WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Date); + } + #endregion + + /// + /// Writes out a comment /*...*/ containing the specified text. + /// + /// Text to place inside the comment. + public void WriteComment(string text) + { + AutoComplete(JsonToken.Comment); + + _writer.Write("/*"); + _writer.Write(text); + _writer.Write("*/"); + } + + /// + /// Writes out the given white space. + /// + /// The string of white space characters. + public void WriteWhitespace(string ws) + { + if (ws != null) + { + if (!StringUtils.IsWhiteSpace(ws)) + throw new JsonWriterException("Only white space characters should be used."); + + _writer.Write(ws); + } + } + + void IDisposable.Dispose() + { + Dispose(true); + } + + private void Dispose(bool disposing) + { + if (WriteState != WriteState.Closed) + Close(); + } + } +} diff --git a/Src/Newtonsoft.Json/JsonWriterException.cs b/Src/Newtonsoft.Json/JsonWriterException.cs new file mode 100644 index 00000000..bc43cd37 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonWriterException.cs @@ -0,0 +1,65 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json +{ + /// + /// The exception thrown when an error occurs while reading Json text. + /// + public class JsonWriterException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public JsonWriterException() + { + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public JsonWriterException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class + /// with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + public JsonWriterException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/Src/Newtonsoft.Json/MemberMapping.cs b/Src/Newtonsoft.Json/MemberMapping.cs new file mode 100644 index 00000000..910f429d --- /dev/null +++ b/Src/Newtonsoft.Json/MemberMapping.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; + +namespace Newtonsoft.Json +{ + internal struct MemberMapping + { + private readonly string _mappingName; + private readonly MemberInfo _member; + private readonly bool _ignored; + private readonly bool _readable; + private readonly bool _writable; + + public MemberMapping(string mappingName, MemberInfo member, bool ignored, bool readable, bool writable) + { + _mappingName = mappingName; + _member = member; + _ignored = ignored; + _readable = readable; + _writable = writable; + } + + public string MappingName + { + get { return _mappingName; } + } + + public MemberInfo Member + { + get { return _member; } + } + + public bool Ignored + { + get { return _ignored; } + } + + public bool Readable + { + get { return _readable; } + } + + public bool Writable + { + get { return _writable; } + } + } +} diff --git a/Src/Newtonsoft.Json/MemberMappingCollection.cs b/Src/Newtonsoft.Json/MemberMappingCollection.cs new file mode 100644 index 00000000..bb002862 --- /dev/null +++ b/Src/Newtonsoft.Json/MemberMappingCollection.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections.ObjectModel; + +namespace Newtonsoft.Json +{ + internal class MemberMappingCollection : KeyedCollection + { + protected override string GetKeyForItem(MemberMapping item) + { + return item.MappingName; + } + + public void AddMapping(MemberMapping memberMapping) + { + if (Contains(memberMapping.MappingName)) + { + // don't overwrite existing mapping with ignored mapping + if (memberMapping.Ignored) + return; + + MemberMapping existingMemberMapping = this[memberMapping.MappingName]; + + if (!existingMemberMapping.Ignored) + { + throw new JsonSerializationException( + string.Format( + "A member with the name '{0}' already exists on {1}. Use the JsonPropertyAttribute to specify another name.", + memberMapping.MappingName, memberMapping.Member.DeclaringType)); + } + else + { + // remove ignored mapping so it can be replaced in collection + Remove(existingMemberMapping); + } + } + + Add(memberMapping); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj new file mode 100644 index 00000000..f5335ba0 --- /dev/null +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -0,0 +1,84 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {A9AE40FF-1A21-414A-9FE7-3BE13644CC6D} + Library + Properties + Newtonsoft.Json + Newtonsoft.Json + false + + + + + + + + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Newtonsoft.Json.XML + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Newtonsoft.Json.XML + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..e17ba8fa --- /dev/null +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -0,0 +1,57 @@ +#region License +// Copyright 2006 James Newton-King +// http://www.newtonsoft.com +// +// This work is licensed under the Creative Commons Attribution 2.5 License +// http://creativecommons.org/licenses/by/2.5/ +// +// You are free: +// * to copy, distribute, display, and perform the work +// * to make derivative works +// * to make commercial use of the work +// +// Under the following conditions: +// * You must attribute the work in the manner specified by the author or licensor: +// - If you find this component useful a link to http://www.newtonsoft.com would be appreciated. +// * For any reuse or distribution, you must make clear to others the license terms of this work. +// * Any of these conditions can be waived if you get permission from the copyright holder. +#endregion + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; + +// 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("Newtonsoft Json.NET")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Newtonsoft")] +[assembly: AssemblyProduct("Newtonsoft Json.NET")] +[assembly: AssemblyCopyright("Copyright © Newtonsoft 2006")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: AllowPartiallyTrustedCallers] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM componenets. 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("9ca358aa-317b-4925-8ada-4a29e943a363")] + +// 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.3.0.0")] +[assembly: AssemblyFileVersion("1.3.0.0")] \ No newline at end of file diff --git a/Src/Newtonsoft.Json/StringBuffer.cs b/Src/Newtonsoft.Json/StringBuffer.cs new file mode 100644 index 00000000..0365799d --- /dev/null +++ b/Src/Newtonsoft.Json/StringBuffer.cs @@ -0,0 +1,90 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json +{ + /// + /// Builds a string. Unlike StringBuilder this class lets you reuse it's internal buffer. + /// + internal class StringBuffer + { + private char[] _buffer; + private int _position; + + private static char[] _emptyBuffer = new char[0]; + + public int Position + { + get { return _position; } + set { _position = value; } + } + + public StringBuffer() + { + _buffer = _emptyBuffer; + } + + public StringBuffer(int initalSize) + { + _buffer = new char[initalSize]; + } + + public void Append(char value) + { + // test if the buffer array is large enough to take the value + if (_position + 1 > _buffer.Length) + { + EnsureSize(1); + } + + // set value and increment poisition + _buffer[_position++] = value; + } + + public void Clear() + { + _buffer = _emptyBuffer; + _position = 0; + } + + private void EnsureSize(int appendLength) + { + char[] newBuffer = new char[_position + appendLength * 2]; + + Array.Copy(_buffer, newBuffer, _position); + + _buffer = newBuffer; + } + + public override string ToString() + { + return new string(_buffer, 0, _position); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs new file mode 100644 index 00000000..6616a3df --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs @@ -0,0 +1,419 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Reflection; +using System.Text; +using System.Collections; + +namespace Newtonsoft.Json.Utilities +{ + internal static class CollectionUtils + { + public static List CreateList(params T[] values) + { + return new List(values); + } + + /// + /// Determines whether the collection is null or empty. + /// + /// The collection. + /// + /// true if the collection is null or empty; otherwise, false. + /// + public static bool IsNullOrEmpty(ICollection collection) + { + if (collection != null) + { + return (collection.Count == 0); + } + return true; + } + + /// + /// Determines whether the collection is null or empty. + /// + /// The collection. + /// + /// true if the collection is null or empty; otherwise, false. + /// + public static bool IsNullOrEmpty(ICollection collection) + { + if (collection != null) + { + return (collection.Count == 0); + } + return true; + } + + /// + /// Determines whether the collection is null, empty or its contents are uninitialized values. + /// + /// The list. + /// + /// true if the collection is null or empty or its contents are uninitialized values; otherwise, false. + /// + public static bool IsNullOrEmptyOrDefault(IList list) + { + if (IsNullOrEmpty(list)) + return true; + + return ReflectionUtils.ItemsUnitializedValue(list); + } + + /// + /// Makes a slice of the specified list in between the start and end indexes. + /// + /// The list. + /// The start index. + /// The end index. + /// A slice of the list. + public static IList Slice(IList list, int? start, int? end) + { + return Slice(list, start, end, null); + } + + /// + /// Makes a slice of the specified list in between the start and end indexes, + /// getting every so many items based upon the step. + /// + /// The list. + /// The start index. + /// The end index. + /// The step. + /// A slice of the list. + public static IList Slice(IList list, int? start, int? end, int? step) + { + if (list == null) + throw new ArgumentNullException("list"); + + if (step == 0) + throw new ArgumentException("Step cannot be zero.", "step"); + + List slicedList = new List(); + + // nothing to slice + if (list.Count == 0) + return slicedList; + + // set defaults for null arguments + int s = step ?? 1; + int startIndex = start ?? 0; + int endIndex = end ?? list.Count; + + // start from the end of the list if start is negitive + startIndex = (startIndex < 0) ? list.Count + startIndex : startIndex; + + // end from the start of the list if end is negitive + endIndex = (endIndex < 0) ? list.Count + endIndex : endIndex; + + // ensure indexes keep within collection bounds + startIndex = Math.Max(startIndex, 0); + endIndex = Math.Min(endIndex, list.Count - 1); + + // loop between start and end indexes, incrementing by the step + for (int i = startIndex; i < endIndex; i += s) + { + slicedList.Add(list[i]); + } + + return slicedList; + } + + + /// + /// Group the collection using a function which returns the key. + /// + /// The source collection to group. + /// The key selector. + /// A Dictionary with each key relating to a list of objects in a list grouped under it. + public static Dictionary> GroupBy(ICollection source, Func keySelector) + { + if (keySelector == null) + throw new ArgumentNullException("keySelector"); + + Dictionary> groupedValues = new Dictionary>(); + + foreach (V value in source) + { + // using delegate to get the value's key + K key = keySelector(value); + List groupedValueList; + + // add a list for grouped values if the key is not already in Dictionary + if (!groupedValues.TryGetValue(key, out groupedValueList)) + { + groupedValueList = new List(); + groupedValues.Add(key, groupedValueList); + } + + groupedValueList.Add(value); + } + + return groupedValues; + } + + /// + /// Adds the elements of the specified collection to the specified generic IList. + /// + /// The list to add to. + /// The collection of elements to add. + public static void AddRange(IList initial, IEnumerable collection) + { + if (initial == null) + throw new ArgumentNullException("initial"); + + if (collection == null) + return; + + foreach (T value in collection) + { + initial.Add(value); + } + } + + public static List Distinct(List collection) + { + List distinctList = new List(); + + foreach (T value in collection) + { + if (!distinctList.Contains(value)) + distinctList.Add(value); + } + + return distinctList; + } + + public static List> Flatten(params IList[] lists) + { + List> flattened = new List>(); + Dictionary currentList = new Dictionary(); + + Recurse(new List>(lists), 0, currentList, flattened); + + return flattened; + } + + private static void Recurse(IList> global, int current, Dictionary currentSet, List> flattenedResult) + { + IList currentArray = global[current]; + + for (int i = 0; i < currentArray.Count; i++) + { + currentSet[current] = currentArray[i]; + + if (current == global.Count - 1) + { + List items = new List(); + + for (int k = 0; k < currentSet.Count; k++) + { + items.Add(currentSet[k]); + } + + flattenedResult.Add(items); + } + else + { + Recurse(global, current + 1, currentSet, flattenedResult); + } + } + } + + public static List CreateList(ICollection collection) + { + if (collection == null) + throw new ArgumentNullException("collection"); + + T[] array = new T[collection.Count]; + collection.CopyTo(array, 0); + + return new List(array); + } + + public static bool ListEquals(IList a, IList b) + { + if (a == null || b == null) + return (a == null && b == null); + + if (a.Count != b.Count) + return false; + + EqualityComparer comparer = EqualityComparer.Default; + + for (int i = 0; i < a.Count; i++) + { + if (!comparer.Equals(a[i], b[i])) + return false; + } + + return true; + } + + #region GetSingleItem + public static bool TryGetSingleItem(IList list, out T value) + { + return TryGetSingleItem(list, false, out value); + } + + public static bool TryGetSingleItem(IList list, bool returnDefaultIfEmpty, out T value) + { + return MiscellaneousUtils.TryAction(delegate { return GetSingleItem(list, returnDefaultIfEmpty); }, out value); + } + + public static T GetSingleItem(IList list) + { + return GetSingleItem(list, false); + } + + public static T GetSingleItem(IList list, bool returnDefaultIfEmpty) + { + if (list.Count == 1) + return list[0]; + else if (returnDefaultIfEmpty && list.Count == 0) + return default(T); + else + throw new Exception(string.Format("Expected single {0} in list but got {1}.", typeof(T), list.Count)); + } + #endregion + + public static IList Minus(IList list, IList minus) + { + ValidationUtils.ArgumentNotNull(list, "list"); + + List result = new List(list.Count); + foreach (T t in list) + { + if (minus == null || !minus.Contains(t)) + result.Add(t); + } + + return result; + } + + public static T[] CreateArray(IEnumerable enumerable) + { + ValidationUtils.ArgumentNotNull(enumerable, "enumerable"); + + if (enumerable is T[]) + return (T[])enumerable; + + List tempList = new List(enumerable); + return tempList.ToArray(); + } + + public static object CreateGenericList(Type listType) + { + ValidationUtils.ArgumentNotNull(listType, "listType"); + + return ReflectionUtils.CreateGeneric(typeof(List<>), listType); + } + + public static bool IsListType(Type type) + { + ValidationUtils.ArgumentNotNull(type, "listType"); + + if (type.IsArray) + return true; + else if (typeof(IList).IsAssignableFrom(type)) + return true; + else if (ReflectionUtils.IsSubClass(type, typeof(IList<>))) + return true; + else + return false; + } + + public static IList CreateAndPopulateList(Type listType, Action populateList) + { + ValidationUtils.ArgumentNotNull(listType, "listType"); + ValidationUtils.ArgumentNotNull(populateList, "populateList"); + + IList list; + Type readOnlyCollectionType; + bool isReadOnlyOrFixedSize = false; + + if (listType.IsArray) + { + // have to use an arraylist when creating array + // there is no way to know the size until it is finised + list = new ArrayList(); + isReadOnlyOrFixedSize = true; + } + else if (ReflectionUtils.IsSubClass(listType, typeof(ReadOnlyCollection<>), out readOnlyCollectionType)) + { + Type readOnlyCollectionContentsType = readOnlyCollectionType.GetGenericArguments()[0]; + Type genericEnumerable = ReflectionUtils.MakeGenericType(typeof(IEnumerable<>), readOnlyCollectionContentsType); + bool suitableConstructor = false; + + foreach (ConstructorInfo constructor in listType.GetConstructors()) + { + IList parameters = constructor.GetParameters(); + + if (parameters.Count == 1) + { + if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType)) + { + suitableConstructor = true; + break; + } + } + } + + if (!suitableConstructor) + throw new Exception(string.Format("Readonly type {0} does not have a public constructor that takes a type that implements {1}.", listType, genericEnumerable)); + + // can't add or modify a readonly list + // use List and convert once populated + list = (IList)CreateGenericList(readOnlyCollectionContentsType); + isReadOnlyOrFixedSize = true; + } + else if (typeof(IList).IsAssignableFrom(listType) && ReflectionUtils.IsInstantiatableType(listType)) + { + list = (IList)Activator.CreateInstance(listType); + } + else + { + throw new Exception(string.Format("Cannot create and populate list type {0}.", listType)); + } + + populateList(list); + + // create readonly and fixed sized collections using the temporary list + if (isReadOnlyOrFixedSize) + { + if (listType.IsArray) + list = ((ArrayList)list).ToArray(ReflectionUtils.GetListItemType(listType)); + else if (ReflectionUtils.IsSubClass(listType, typeof(ReadOnlyCollection<>))) + list = (IList)Activator.CreateInstance(listType, list); + } + + return list; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs new file mode 100644 index 00000000..7bedfbb9 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs @@ -0,0 +1,137 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections; +using System.Globalization; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using System.Web; +using System.Collections.Generic; +using System.Drawing; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace Newtonsoft.Json.Utilities +{ + internal static class JavaScriptUtils + { + public static string GetCallbackEventFunction(Page page, Control control) + { + string script = page.ClientScript.GetCallbackEventReference(control, "eventArgument", "eventCallback", "context", "errorCallback", true); + + script = "function(eventArgument,eventCallback,context,errorCallback){" + script + "}"; + + return script; + } + + public static string GetCallbackEventFunction(Page page, Control control, string argument) + { + string script = page.ClientScript.GetCallbackEventReference(control, "'" + argument + "'", "eventCallback", "context", "errorCallback", true); + + script = "function(eventCallback,context,errorCallback){" + script + "}"; + + return script; + } + + public static void WriteEscapedJavaScriptChar(TextWriter writer, char c, char delimiter) + { + switch (c) + { + case '\t': + writer.Write(@"\t"); + break; + case '\n': + writer.Write(@"\n"); + break; + case '\r': + writer.Write(@"\r"); + break; + case '\f': + writer.Write(@"\f"); + break; + case '\b': + writer.Write(@"\b"); + break; + case '\\': + writer.Write(@"\\"); + break; + //case '<': + //case '>': + //case '\'': + // StringUtils.WriteCharAsUnicode(writer, c); + // break; + case '"': + // only escape if this charater is being used as the delimiter + writer.Write((delimiter == '"') ? "\\\"" : null); + break; + default: + if (c > '\u001f') + writer.Write(c); + else + StringUtils.WriteCharAsUnicode(writer, c); + break; + } + } + + public static void WriteEscapedJavaScriptString(TextWriter writer, string value, char delimiter, bool appendDelimiters) + { + // leading delimiter + if (appendDelimiters) + writer.Write(delimiter); + + if (value != null) + { + for (int i = 0; i < value.Length; i++) + { + WriteEscapedJavaScriptChar(writer, value[i], delimiter); + } + } + + // trailing delimiter + if (appendDelimiters) + writer.Write(delimiter); + } + + public static string ToEscapedJavaScriptString(string value) + { + return ToEscapedJavaScriptString(value, '"', true); + } + + public static string ToEscapedJavaScriptString(string value, char delimiter, bool appendDelimiters) + { + using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(value) ?? 16)) + { + WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters); + return w.ToString(); + } + } + } +} + + + + diff --git a/Src/Newtonsoft.Json/Utilities/MathUtils.cs b/Src/Newtonsoft.Json/Utilities/MathUtils.cs new file mode 100644 index 00000000..26a6b889 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/MathUtils.cs @@ -0,0 +1,60 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json.Utilities +{ + internal class MathUtils + { + public static int HexToInt(char h) + { + if ((h >= '0') && (h <= '9')) + { + return (h - '0'); + } + if ((h >= 'a') && (h <= 'f')) + { + return ((h - 'a') + 10); + } + if ((h >= 'A') && (h <= 'F')) + { + return ((h - 'A') + 10); + } + return -1; + } + + public static char IntToHex(int n) + { + if (n <= 9) + { + return (char)(n + 48); + } + return (char)((n - 10) + 97); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs new file mode 100644 index 00000000..00d81359 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using System.Text; + +namespace Newtonsoft.Json.Utilities +{ + internal delegate void Action(); + internal delegate T Creator(); + internal delegate T Func(A0 arg0); + internal delegate T Func(A0 arg0, A1 arg1); + internal delegate T Func(A0 arg0, A1 arg1, A2 arg2); + + internal static class MiscellaneousUtils + { + public static bool TryAction(Creator creator, out T output) + { + ValidationUtils.ArgumentNotNull(creator, "creator"); + + try + { + output = creator(); + return true; + } + catch + { + output = default(T); + return false; + } + } + + public static bool TryGetDescription(object value, out string description) + { + return TryAction(delegate { return GetDescription(value); }, out description); + } + + public static string GetDescription(object o) + { + ValidationUtils.ArgumentNotNull(o, "o"); + + ICustomAttributeProvider attributeProvider = o as ICustomAttributeProvider; + + // object passed in isn't an attribute provider + // if value is an enum value, get value field member, otherwise get values type + if (attributeProvider == null) + { + Type valueType = o.GetType(); + + if (valueType.IsEnum) + attributeProvider = valueType.GetField(o.ToString()); + else + attributeProvider = valueType; + } + + DescriptionAttribute descriptionAttribute = ReflectionUtils.GetAttribute(attributeProvider); + + if (descriptionAttribute != null) + return descriptionAttribute.Description; + else + throw new Exception(string.Format("No DescriptionAttribute on '{0}'.", o.GetType())); + } + + public static IList GetDescriptions(IList values) + { + ValidationUtils.ArgumentNotNull(values, "values"); + + string[] descriptions = new string[values.Count]; + + for (int i = 0; i < values.Count; i++) + { + descriptions[i] = GetDescription(values[i]); + } + + return descriptions; + } + + public static string ToString(object value) + { + return (value != null) ? value.ToString() : "{null}"; + } + } +} diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs new file mode 100644 index 00000000..75561e56 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -0,0 +1,524 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Collections; +using System.ComponentModel; + +namespace Newtonsoft.Json.Utilities +{ + internal static class ReflectionUtils + { + public static Type GetObjectType(object v) + { + return (v != null) ? v.GetType() : null; + } + + public static bool IsInstantiatableType(Type t) + { + ValidationUtils.ArgumentNotNull(t, "t"); + + if (t.IsAbstract || t.IsInterface || t.IsArray || t.IsGenericTypeDefinition || t == typeof(void)) + return false; + + if (!HasDefaultConstructor(t)) + return false; + + return true; + } + + public static bool HasDefaultConstructor(Type t) + { + ValidationUtils.ArgumentNotNull(t, "t"); + + if (t.IsValueType) + return true; + + return (t.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null) != null); + } + + public static bool IsNullable(Type t) + { + ValidationUtils.ArgumentNotNull(t, "t"); + + if (t.IsValueType) + return IsNullableType(t); + + return true; + } + + public static bool IsNullableType(Type t) + { + ValidationUtils.ArgumentNotNull(t, "t"); + + return (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)); + } + + //public static bool IsValueTypeUnitializedValue(ValueType value) + //{ + // if (value == null) + // return true; + + // return value.Equals(CreateUnitializedValue(value.GetType())); + //} + + public static bool IsUnitializedValue(object value) + { + if (value == null) + { + return true; + } + else + { + object unitializedValue = CreateUnitializedValue(value.GetType()); + return value.Equals(unitializedValue); + } + } + + public static object CreateUnitializedValue(Type type) + { + ValidationUtils.ArgumentNotNull(type, "type"); + + if (type.IsGenericTypeDefinition) + throw new ArgumentException(string.Format("Type {0} is a generic type definition and cannot be instantiated.", type), "type"); + + if (type.IsClass || type.IsInterface || type == typeof(void)) + return null; + else if (type.IsValueType) + return Activator.CreateInstance(type); + else + throw new ArgumentException(string.Format("Type {0} cannot be instantiated.", type), "type"); + } + + public static bool IsPropertyIndexed(PropertyInfo property) + { + ValidationUtils.ArgumentNotNull(property, "property"); + + return !CollectionUtils.IsNullOrEmpty(property.GetIndexParameters()); + } + + public static bool IsSubClass(Type type, Type check) + { + Type implementingType; + return IsSubClass(type, check, out implementingType); + } + + public static bool IsSubClass(Type type, Type check, out Type implementingType) + { + ValidationUtils.ArgumentNotNull(type, "type"); + ValidationUtils.ArgumentNotNull(check, "check"); + + return IsSubClassInternal(type, type, check, out implementingType); + } + + private static bool IsSubClassInternal(Type initialType, Type currentType, Type check, out Type implementingType) + { + if (currentType == check) + { + implementingType = currentType; + return true; + } + + // don't get interfaces for an interface unless the initial type is an interface + if (check.IsInterface && (initialType.IsInterface || currentType == initialType)) + { + foreach (Type t in currentType.GetInterfaces()) + { + if (IsSubClassInternal(initialType, t, check, out implementingType)) + { + // don't return the interface itself, return it's implementor + if (check == implementingType) + implementingType = currentType; + + return true; + } + } + } + + if (currentType.IsGenericType && !currentType.IsGenericTypeDefinition) + { + if (IsSubClassInternal(initialType, currentType.GetGenericTypeDefinition(), check, out implementingType)) + { + implementingType = currentType; + return true; + } + } + + if (currentType.BaseType == null) + { + implementingType = null; + return false; + } + + return IsSubClassInternal(initialType, currentType.BaseType, check, out implementingType); + } + + /// + /// Gets the type of the typed list's items. + /// + /// The type. + /// The type of the typed list's items. + public static Type GetListItemType(Type type) + { + ValidationUtils.ArgumentNotNull(type, "type"); + Type genericListType; + + if (type.IsArray) + { + return type.GetElementType(); + } + else if (IsSubClass(type, typeof(IList<>), out genericListType)) + { + if (genericListType.IsGenericTypeDefinition) + throw new Exception(string.Format("Type {0} is not a list.", type)); + + return genericListType.GetGenericArguments()[0]; + } + else if (typeof(IList).IsAssignableFrom(type)) + { + return null; + } + else + { + throw new Exception(string.Format("Type {0} is not a list.", type)); + } + } + + public static Type GetDictionaryValueType(Type type) + { + ValidationUtils.ArgumentNotNull(type, "type"); + + Type genericDictionaryType; + if (IsSubClass(type, typeof(IDictionary<,>), out genericDictionaryType)) + { + if (genericDictionaryType.IsGenericTypeDefinition) + throw new Exception(string.Format("Type {0} is not a dictionary.", type)); + + return genericDictionaryType.GetGenericArguments()[1]; + } + else if (typeof(IDictionary).IsAssignableFrom(type)) + { + return null; + } + else + { + throw new Exception(string.Format("Type {0} is not a dictionary.", type)); + } + } + + /// + /// Tests whether the list's items are their unitialized value. + /// + /// The list. + /// Whether the list's items are their unitialized value + public static bool ItemsUnitializedValue(IList list) + { + ValidationUtils.ArgumentNotNull(list, "list"); + + Type elementType = GetListItemType(list.GetType()); + + if (elementType.IsValueType) + { + object unitializedValue = CreateUnitializedValue(elementType); + + for (int i = 0; i < list.Count; i++) + { + if (!list[i].Equals(unitializedValue)) + return false; + } + } + else if (elementType.IsClass) + { + for (int i = 0; i < list.Count; i++) + { + object value = list[i]; + + if (value != null) + return false; + } + } + else + { + throw new Exception(string.Format("Type {0} is neither a ValueType or a Class.", elementType)); + } + + return true; + } + + /// + /// Gets the member's underlying type. + /// + /// The member. + /// The underlying type of the member. + public static Type GetMemberUnderlyingType(MemberInfo member) + { + ValidationUtils.ArgumentNotNull(member, "member"); + + switch (member.MemberType) + { + case MemberTypes.Field: + return ((FieldInfo)member).FieldType; + case MemberTypes.Property: + return ((PropertyInfo)member).PropertyType; + case MemberTypes.Event: + return ((EventInfo)member).EventHandlerType; + default: + throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", "member"); + } + } + + /// + /// Determines whether the member is an indexed property. + /// + /// The member. + /// + /// true if the member is an indexed property; otherwise, false. + /// + public static bool IsIndexedProperty(MemberInfo member) + { + ValidationUtils.ArgumentNotNull(member, "member"); + + PropertyInfo propertyInfo = member as PropertyInfo; + + if (propertyInfo != null) + return IsIndexedProperty(propertyInfo); + else + return false; + } + + /// + /// Determines whether the property is an indexed property. + /// + /// The property. + /// + /// true if the property is an indexed property; otherwise, false. + /// + public static bool IsIndexedProperty(PropertyInfo property) + { + ValidationUtils.ArgumentNotNull(property, "property"); + + return (property.GetIndexParameters().Length > 0); + } + + public static MemberInfo GetMember(Type type, string name, MemberTypes memberTypes) + { + return GetMember(type, name, memberTypes, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + } + + public static MemberInfo GetMember(Type type, string name, MemberTypes memberTypes, BindingFlags bindingAttr) + { + ValidationUtils.ArgumentNotNull(type, "type"); + ValidationUtils.ArgumentNotNull(name, "name"); + + MemberInfo[] result = type.GetMember(name, memberTypes, bindingAttr); + + return CollectionUtils.GetSingleItem(result); + } + + /// + /// Gets the member's value on the object. + /// + /// The member. + /// The target object. + /// The member's value on the object. + public static object GetMemberValue(MemberInfo member, object target) + { + ValidationUtils.ArgumentNotNull(member, "member"); + ValidationUtils.ArgumentNotNull(target, "target"); + + switch (member.MemberType) + { + case MemberTypes.Field: + return ((FieldInfo)member).GetValue(target); + case MemberTypes.Property: + try + { + return ((PropertyInfo)member).GetValue(target, null); + } + catch (TargetParameterCountException e) + { + throw new ArgumentException(string.Format("MemberInfo '{0}' has index parameters", member.Name), "member", e); + } + default: + throw new ArgumentException(string.Format("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo", member.Name), "member"); + } + } + + /// + /// Sets the member's value on the target object. + /// + /// The member. + /// The target. + /// The value. + public static void SetMemberValue(MemberInfo member, object target, object value) + { + ValidationUtils.ArgumentNotNull(member, "member"); + ValidationUtils.ArgumentNotNull(target, "target"); + + switch (member.MemberType) + { + case MemberTypes.Field: + ((FieldInfo)member).SetValue(target, value); + break; + case MemberTypes.Property: + ((PropertyInfo)member).SetValue(target, value, null); + break; + default: + throw new ArgumentException(string.Format("MemberInfo '{0}' must be of type FieldInfo or PropertyInfo", member.Name), "member"); + } + } + + /// + /// Determines whether the specified MemberInfo can be read. + /// + /// The MemberInfo to determine whether can be read. + /// + /// true if the specified MemberInfo can be read; otherwise, false. + /// + public static bool CanReadMemberValue(MemberInfo member) + { + switch (member.MemberType) + { + case MemberTypes.Field: + return true; + case MemberTypes.Property: + return ((PropertyInfo)member).CanRead; + default: + return false; + } + } + + /// + /// Determines whether the specified MemberInfo can be set. + /// + /// The MemberInfo to determine whether can be set. + /// + /// true if the specified MemberInfo can be set; otherwise, false. + /// + public static bool CanSetMemberValue(MemberInfo member) + { + switch (member.MemberType) + { + case MemberTypes.Field: + return true; + case MemberTypes.Property: + return ((PropertyInfo)member).CanWrite; + default: + return false; + } + } + + public static List GetFieldsAndProperties(BindingFlags bindingAttr) + { + return GetFieldsAndProperties(typeof(T), bindingAttr); + } + + public static List GetFieldsAndProperties(Type type, BindingFlags bindingAttr) + { + List targetMembers = new List(); + + targetMembers.AddRange(type.GetFields(bindingAttr)); + targetMembers.AddRange(type.GetProperties(bindingAttr)); + + return targetMembers; + } + + public static T GetAttribute(ICustomAttributeProvider attributeProvider) where T : Attribute + { + return GetAttribute(attributeProvider, true); + } + + public static T GetAttribute(ICustomAttributeProvider attributeProvider, bool inherit) where T : Attribute + { + T[] attributes = GetAttributes(attributeProvider, inherit); + + return CollectionUtils.GetSingleItem(attributes, true); + } + + public static T[] GetAttributes(ICustomAttributeProvider attributeProvider, bool inherit) where T : Attribute + { + ValidationUtils.ArgumentNotNull(attributeProvider, "attributeProvider"); + + return (T[])attributeProvider.GetCustomAttributes(typeof(T), inherit); + } + + public static string GetNameAndAssessmblyName(Type t) + { + ValidationUtils.ArgumentNotNull(t, "t"); + + return t.FullName + ", " + t.Assembly.GetName().Name; + } + + public static List FindMembers(Type targetType, MemberTypes memberType, BindingFlags bindingAttr, MemberFilter filter, object filterCriteria) + { + ValidationUtils.ArgumentNotNull(targetType, "targetType"); + + List memberInfos = new List(targetType.FindMembers(memberType, bindingAttr, filter, filterCriteria)); + + // fix weirdness with FieldInfos only being returned for the current Type + // find base type fields and add them to result + if ((memberType & MemberTypes.Field) != 0 + && (bindingAttr & BindingFlags.NonPublic) != 0) + { + // modify flags to not search for public fields + BindingFlags nonPublicBindingAttr = bindingAttr ^ BindingFlags.Public; + + while ((targetType = targetType.BaseType) != null) + { + memberInfos.AddRange(targetType.FindMembers(MemberTypes.Field, nonPublicBindingAttr, filter, filterCriteria)); + } + } + + return memberInfos; + } + + public static Type MakeGenericType(Type genericTypeDefinition, params Type[] innerTypes) + { + ValidationUtils.ArgumentNotNull(genericTypeDefinition, "genericTypeDefinition"); + ValidationUtils.ArgumentNotNullOrEmpty(innerTypes, "innerTypes"); + ValidationUtils.ArgumentConditionTrue(genericTypeDefinition.IsGenericTypeDefinition, "genericTypeDefinition", string.Format("Type {0} is not a generic type definition.", genericTypeDefinition)); + + return genericTypeDefinition.MakeGenericType(innerTypes); + } + + public static object CreateGeneric(Type genericTypeDefinition, Type innerType, params object[] args) + { + return CreateGeneric(genericTypeDefinition, new Type[] { innerType }, args); + } + + public static object CreateGeneric(Type genericTypeDefinition, IList innerTypes, params object[] args) + { + ValidationUtils.ArgumentNotNull(genericTypeDefinition, "genericTypeDefinition"); + ValidationUtils.ArgumentNotNullOrEmpty(innerTypes, "innerTypes"); + + Type specificType = MakeGenericType(genericTypeDefinition, CollectionUtils.CreateArray(innerTypes)); + + return Activator.CreateInstance(specificType, args); + } + } +} diff --git a/Src/Newtonsoft.Json/Utilities/StringUtils.cs b/Src/Newtonsoft.Json/Utilities/StringUtils.cs new file mode 100644 index 00000000..8861c15a --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/StringUtils.cs @@ -0,0 +1,396 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections.Generic; +using System.Data.SqlTypes; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; + +namespace Newtonsoft.Json.Utilities +{ + internal static class StringUtils + { + public const string CarriageReturnLineFeed = "\r\n"; + public const string Empty = ""; + public const char CarriageReturn = '\r'; + public const char LineFeed = '\n'; + public const char Tab = '\t'; + + /// + /// Determines whether the string contains white space. + /// + /// The string to test for white space. + /// + /// true if the string contains white space; otherwise, false. + /// + public static bool ContainsWhiteSpace(string s) + { + if (s == null) + throw new ArgumentNullException("s"); + + for (int i = 0; i < s.Length; i++) + { + if (char.IsWhiteSpace(s[i])) + return true; + } + return false; + } + + /// + /// Determines whether the string is all white space. Empty string will return false. + /// + /// The string to test whether it is all white space. + /// + /// true if the string is all white space; otherwise, false. + /// + public static bool IsWhiteSpace(string s) + { + if (s == null) + throw new ArgumentNullException("s"); + + if (s.Length == 0) + return false; + + for (int i = 0; i < s.Length; i++) + { + if (!char.IsWhiteSpace(s[i])) + return false; + } + + return true; + } + + /// + /// Ensures the target string ends with the specified string. + /// + /// The target. + /// The value. + /// The target string with the value string at the end. + public static string EnsureEndsWith(string target, string value) + { + if (target == null) + throw new ArgumentNullException("target"); + + if (value == null) + throw new ArgumentNullException("value"); + + if (target.Length >= value.Length) + { + if (string.Compare(target, target.Length - value.Length, value, 0, value.Length, StringComparison.OrdinalIgnoreCase) == + 0) + return target; + + string trimmedString = target.TrimEnd(null); + + if (string.Compare(trimmedString, trimmedString.Length - value.Length, value, 0, value.Length, + StringComparison.OrdinalIgnoreCase) == 0) + return target; + } + + return target + value; + } + + /// + /// Determines whether the SqlString is null or empty. + /// + /// The string. + /// + /// true if the SqlString is null or empty; otherwise, false. + /// + public static bool IsNullOrEmpty(SqlString s) + { + if (s.IsNull) + return true; + else + return string.IsNullOrEmpty(s.Value); + } + + public static bool IsNullOrEmptyOrWhiteSpace(string s) + { + if (string.IsNullOrEmpty(s)) + return true; + else if (IsWhiteSpace(s)) + return true; + else + return false; + } + + /// + /// Perform an action if the string is not null or empty. + /// + /// The value. + /// The action to perform. + public static void IfNotNullOrEmpty(string value, Action action) + { + IfNotNullOrEmpty(value, action, null); + } + + private static void IfNotNullOrEmpty(string value, Action trueAction, Action falseAction) + { + if (!string.IsNullOrEmpty(value)) + { + if (trueAction != null) + trueAction(value); + } + else + { + if (falseAction != null) + falseAction(value); + } + } + + /// + /// Indents the specified string. + /// + /// The string to indent. + /// The number of characters to indent by. + /// + public static string Indent(string s, int indentation) + { + return Indent(s, indentation, ' '); + } + + /// + /// Indents the specified string. + /// + /// The string to indent. + /// The number of characters to indent by. + /// The indent character. + /// + public static string Indent(string s, int indentation, char indentChar) + { + if (s == null) + throw new ArgumentNullException("s"); + + if (indentation <= 0) + throw new ArgumentException("Must be greater than zero.", "indentation"); + + StringReader sr = new StringReader(s); + StringWriter sw = new StringWriter(); + + ActionTextReaderLine(sr, sw, delegate(TextWriter tw, string line) + { + tw.Write(new string(indentChar, indentation)); + tw.Write(line); + }); + + return sw.ToString(); + } + + private delegate void ActionLine(TextWriter textWriter, string line); + + private static void ActionTextReaderLine(TextReader textReader, TextWriter textWriter, ActionLine lineAction) + { + string line; + bool firstLine = true; + while ((line = textReader.ReadLine()) != null) + { + if (!firstLine) + textWriter.WriteLine(); + else + firstLine = false; + + lineAction(textWriter, line); + } + } + + /// + /// Numbers the lines. + /// + /// The string to number. + /// + public static string NumberLines(string s) + { + if (s == null) + throw new ArgumentNullException("s"); + + StringReader sr = new StringReader(s); + StringWriter sw = new StringWriter(); + + int lineNumber = 1; + + ActionTextReaderLine(sr, sw, delegate(TextWriter tw, string line) + { + tw.Write(lineNumber.ToString().PadLeft(4)); + tw.Write(". "); + tw.Write(line); + + lineNumber++; + }); + + return sw.ToString(); + } + + /// + /// Nulls an empty string. + /// + /// The string. + /// Null if the string was null, otherwise the string unchanged. + public static string NullEmptyString(string s) + { + return (string.IsNullOrEmpty(s)) ? null : s; + } + + public static string ReplaceNewLines(string s, string replacement) + { + StringReader sr = new StringReader(s); + StringBuilder sb = new StringBuilder(); + + bool first = true; + + string line; + while ((line = sr.ReadLine()) != null) + { + if (first) + first = false; + else + sb.Append(replacement); + + sb.Append(line); + } + + return sb.ToString(); + } + + public static string RemoveHtml(string s) + { + return RemoveHtmlInternal(s, null); + } + + public static string RemoveHtml(string s, IList removeTags) + { + if (removeTags == null) + throw new ArgumentNullException("removeTags"); + + return RemoveHtmlInternal(s, removeTags); + } + + private static string RemoveHtmlInternal(string s, IList removeTags) + { + List removeTagsUpper = null; + + if (removeTags != null) + { + removeTagsUpper = new List(removeTags.Count); + + foreach (string tag in removeTags) + { + removeTagsUpper.Add(tag.ToUpperInvariant()); + } + } + + Regex anyTag = new Regex(@"<[/]{0,1}\s*(?\w*)\s*(?.*?=['""].*?[""'])*?\s*[/]{0,1}>", RegexOptions.Compiled); + + return anyTag.Replace(s, delegate(Match match) + { + string tag = match.Groups["tag"].Value.ToUpperInvariant(); + + if (removeTagsUpper == null) + return string.Empty; + else if (removeTagsUpper.Contains(tag)) + return string.Empty; + else + return match.Value; + }); + } + + public static string Truncate(string s, int maximumLength) + { + return Truncate(s, maximumLength, "..."); + } + + public static string Truncate(string s, int maximumLength, string suffix) + { + if (suffix == null) + throw new ArgumentNullException("suffix"); + + if (maximumLength <= 0) + throw new ArgumentException("Maximum length must be greater than zero.", "maximumLength"); + + int subStringLength = maximumLength - suffix.Length; + + if (subStringLength <= 0) + throw new ArgumentException("Length of suffix string is greater or equal to maximumLength"); + + if (s != null && s.Length > maximumLength) + { + string truncatedString = s.Substring(0, subStringLength); + // incase the last character is a space + truncatedString = truncatedString.Trim(); + truncatedString += suffix; + + return truncatedString; + } + else + { + return s; + } + } + + public static StringWriter CreateStringWriter(int capacity) + { + StringBuilder sb = new StringBuilder(capacity); + StringWriter sw = new StringWriter(sb); + + return sw; + } + + public static int? GetLength(string value) + { + if (value == null) + return null; + else + return value.Length; + } + + public static string ToCharAsUnicode(char c) + { + using (StringWriter w = new StringWriter()) + { + WriteCharAsUnicode(w, c); + return w.ToString(); + } + } + + public static void WriteCharAsUnicode(TextWriter writer, char c) + { + ValidationUtils.ArgumentNotNull(writer, "writer"); + + char h1 = MathUtils.IntToHex((c >> 12) & '\x000f'); + char h2 = MathUtils.IntToHex((c >> 8) & '\x000f'); + char h3 = MathUtils.IntToHex((c >> 4) & '\x000f'); + char h4 = MathUtils.IntToHex(c & '\x000f'); + + writer.Write('\\'); + writer.Write('u'); + writer.Write(h1); + writer.Write(h2); + writer.Write(h3); + writer.Write(h4); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs b/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs new file mode 100644 index 00000000..aae4e057 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs @@ -0,0 +1,148 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// 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. +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Newtonsoft.Json.Utilities +{ + internal static class ValidationUtils + { + public const string EmailAddressRegex = @"^([a-zA-Z0-9_'+*$%\^&!\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9:]{2,4})+$"; + public const string CurrencyRegex = @"(^\$?(?!0,?\d)\d{1,3}(,?\d{3})*(\.\d\d)?)$"; + public const string DateRegex = + @"^(((0?[1-9]|[12]\d|3[01])[\.\-\/](0?[13578]|1[02])[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|((0?[1-9]|[12]\d|30)[\.\-\/](0?[13456789]|1[012])[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|((0?[1-9]|1\d|2[0-8])[\.\-\/]0?2[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|(29[\.\-\/]0?2[\.\-\/]((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)|00|[048])))$"; + public const string NumericRegex = @"\d*"; + + public static void ArgumentNotNullOrEmpty(string value, string parameterName) + { + if (value == null) + throw new ArgumentNullException(parameterName); + + if (value.Length == 0) + throw new ArgumentException(string.Format("'{0}' cannot be empty.", parameterName), parameterName); + } + + public static void ArgumentNotNullOrEmptyOrWhitespace(string value, string parameterName) + { + ArgumentNotNullOrEmpty(value, parameterName); + + if (StringUtils.IsWhiteSpace(value)) + throw new ArgumentException(string.Format("'{0}' cannot only be whitespace.", parameterName), parameterName); + } + + public static void ArgumentTypeIsEnum(Type enumType, string parameterName) + { + ArgumentNotNull(enumType, "enumType"); + + if (!enumType.IsEnum) + throw new ArgumentException(string.Format("Type {0} is not an Enum.", enumType), parameterName); + } + + public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName) + { + ArgumentNotNullOrEmpty(collection, parameterName, string.Format("Collection '{0}' cannot be empty.", parameterName)); + } + + public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName, string message) + { + if (collection == null) + throw new ArgumentNullException(parameterName); + + if (collection.Count == 0) + throw new ArgumentException(message, parameterName); + } + + public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName) + { + ArgumentNotNullOrEmpty(collection, parameterName, string.Format("Collection '{0}' cannot be empty.", parameterName)); + } + + public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName, string message) + { + if (collection == null) + throw new ArgumentNullException(parameterName); + + if (collection.Count == 0) + throw new ArgumentException(message, parameterName); + } + + public static void ArgumentNotNull(object value, string parameterName) + { + if (value == null) + throw new ArgumentNullException(parameterName); + } + + public static void ArgumentNotNegative(int value, string parameterName) + { + if (value <= 0) + throw new ArgumentOutOfRangeException(parameterName, value, "Argument cannot be negative."); + } + + public static void ArgumentNotNegative(int value, string parameterName, string message) + { + if (value <= 0) + throw new ArgumentOutOfRangeException(parameterName, value, message); + } + + public static void ArgumentNotZero(int value, string parameterName) + { + if (value == 0) + throw new ArgumentOutOfRangeException(parameterName, value, "Argument cannot be zero."); + } + + public static void ArgumentNotZero(int value, string parameterName, string message) + { + if (value == 0) + throw new ArgumentOutOfRangeException(parameterName, value, message); + } + + public static void ArgumentIsPositive(T value, string parameterName) where T : struct, IComparable + { + if (value.CompareTo(default(T)) != 1) + throw new ArgumentOutOfRangeException(parameterName, value, "Positive number required."); + } + + public static void ArgumentIsPositive(int value, string parameterName, string message) + { + if (value > 0) + throw new ArgumentOutOfRangeException(parameterName, value, message); + } + + public static void ObjectNotDisposed(bool disposed, Type objectType) + { + if (disposed) + throw new ObjectDisposedException(objectType.Name); + } + + public static void ArgumentConditionTrue(bool condition, string parameterName, string message) + { + if (!condition) + throw new ArgumentException(message, parameterName); + } + } +} \ No newline at end of file