2
0

JsonWriterTest.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. //
  2. // JsonWriterTest.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using System.IO;
  30. using System.Text;
  31. using System.Runtime.Serialization;
  32. using System.Runtime.Serialization.Json;
  33. using System.Xml;
  34. using NUnit.Framework;
  35. namespace MonoTests.System.Runtime.Serialization.Json
  36. {
  37. [TestFixture]
  38. public class JsonWriterTest
  39. {
  40. MemoryStream ms;
  41. XmlDictionaryWriter w;
  42. string ResultString {
  43. get { return Encoding.UTF8.GetString (ms.ToArray ()); }
  44. }
  45. [SetUp]
  46. public void Setup ()
  47. {
  48. ms = new MemoryStream ();
  49. w = JsonReaderWriterFactory.CreateJsonWriter (ms);
  50. }
  51. /*
  52. [Test]
  53. public void Dummy_BitFlagsGenerator ()
  54. {
  55. var b = new BitFlagsGenerator (2);
  56. Assert.IsFalse (b.Load (0), "#a1");
  57. b.Store (0, false);
  58. Assert.IsFalse (b.Load (0), "#a2");
  59. b.Store (0, true);
  60. Assert.IsTrue (b.Load (0), "#a3");
  61. Assert.IsFalse (b.Load (1), "#a4");
  62. b.Store (0, false);
  63. Assert.IsFalse (b.Load (0), "#a5");
  64. Assert.IsFalse (b.Load (1), "#a6");
  65. Assert.IsFalse (b.Load (1), "#b1");
  66. b.Store (1, false);
  67. Assert.IsFalse (b.Load (1), "#b2");
  68. b.Store (1, true);
  69. Assert.IsTrue (b.Load (1), "#b3");
  70. b.Store (1, false);
  71. Assert.IsFalse (b.Load (1), "#b4");
  72. var bytes = new byte [2];
  73. Assert.IsFalse (BitFlagsGenerator.IsBitSet (bytes, 0), "#c1");
  74. BitFlagsGenerator.SetBit (bytes, 0);
  75. Assert.IsTrue (BitFlagsGenerator.IsBitSet (bytes, 0), "#c2");
  76. Assert.IsFalse (BitFlagsGenerator.IsBitSet (bytes, 1), "#c3");
  77. BitFlagsGenerator.SetBit (bytes, 0);
  78. Assert.IsTrue (BitFlagsGenerator.IsBitSet (bytes, 0), "#c4");
  79. }
  80. */
  81. [Test]
  82. [ExpectedException (typeof (ArgumentNullException))]
  83. public void ConstructorNullStream ()
  84. {
  85. JsonReaderWriterFactory.CreateJsonWriter (null);
  86. }
  87. [Test]
  88. [ExpectedException (typeof (ArgumentNullException))]
  89. public void ConstructorNullEncoding ()
  90. {
  91. JsonReaderWriterFactory.CreateJsonWriter (new MemoryStream (), null);
  92. }
  93. [Test]
  94. [ExpectedException (typeof (XmlException))]
  95. public void SimpleElementNotRoot ()
  96. {
  97. w.WriteStartElement ("foo");
  98. }
  99. [Test]
  100. public void SimpleElement ()
  101. {
  102. w.WriteStartElement ("root");
  103. w.WriteEndElement ();
  104. w.Close ();
  105. // empty string literal ("")
  106. Assert.AreEqual ("\"\"", ResultString, "#1");
  107. }
  108. [Test]
  109. [ExpectedException (typeof (XmlException))]
  110. public void SimpleElement2 ()
  111. {
  112. w.WriteStartElement ("root");
  113. w.WriteStartElement ("foo");
  114. // type='array' or type='object' is required before writing immediate child of an element.
  115. }
  116. [Test]
  117. public void SimpleElement3 ()
  118. {
  119. w.WriteStartElement ("root");
  120. w.WriteAttributeString ("type", "object");
  121. w.WriteStartElement ("e1");
  122. w.WriteAttributeString ("type", "object");
  123. w.WriteStartElement ("e1_1");
  124. w.WriteEndElement (); // treated as a string literal
  125. w.WriteEndElement ();
  126. w.WriteStartElement ("e2");
  127. w.WriteString ("value");
  128. w.WriteEndElement ();
  129. w.WriteEndElement ();
  130. w.Close ();
  131. string json = "{\"e1\":{\"e1_1\":\"\"},\"e2\":\"value\"}";
  132. Assert.AreEqual (json, ResultString, "#1");
  133. }
  134. [Test]
  135. [ExpectedException (typeof (ArgumentException))]
  136. public void AttributeNonType ()
  137. {
  138. w.WriteStartElement ("root");
  139. // only "type" attribute is expected.
  140. w.WriteStartAttribute ("a1");
  141. }
  142. [Test]
  143. [ExpectedException (typeof (XmlException))]
  144. public void TypeAttributeNonStandard ()
  145. {
  146. w.WriteStartElement ("root");
  147. w.WriteAttributeString ("type", "foo");
  148. }
  149. [Test]
  150. public void SimpleTypeAttribute ()
  151. {
  152. w.WriteStartElement ("root");
  153. w.WriteAttributeString ("type", "number");
  154. w.WriteEndElement ();
  155. w.Close ();
  156. Assert.AreEqual (String.Empty, ResultString, "#1");
  157. }
  158. [Test]
  159. public void SimpleTypeAttribute2 ()
  160. {
  161. w.WriteStartElement ("root");
  162. w.WriteAttributeString ("type", "object");
  163. w.WriteStartElement ("foo");
  164. w.WriteAttributeString ("type", "number");
  165. w.WriteString ("1");
  166. w.WriteEndElement ();
  167. w.Close ();
  168. Assert.AreEqual ("{\"foo\":1}", ResultString, "#1");
  169. }
  170. [Test]
  171. [ExpectedException (typeof (XmlException))]
  172. public void WriteStringForNull ()
  173. {
  174. w.WriteStartElement ("root");
  175. w.WriteStartElement ("foo");
  176. w.WriteAttributeString ("type", "null");
  177. w.WriteString ("1");
  178. }
  179. [Test]
  180. [ExpectedException (typeof (XmlException))]
  181. public void WriteStringForArray ()
  182. {
  183. w.WriteStartElement ("root");
  184. w.WriteAttributeString ("type", "object");
  185. w.WriteStartElement ("foo");
  186. w.WriteAttributeString ("type", "array");
  187. w.WriteString ("1");
  188. }
  189. [Test]
  190. // uh, no exception?
  191. public void WriteStringForBoolean ()
  192. {
  193. w.WriteStartElement ("root");
  194. w.WriteAttributeString ("type", "object");
  195. w.WriteStartElement ("foo");
  196. w.WriteAttributeString ("type", "boolean");
  197. w.WriteString ("xyz");
  198. w.WriteEndElement ();
  199. }
  200. [Test]
  201. [ExpectedException (typeof (XmlException))]
  202. public void WriteStringForObject ()
  203. {
  204. w.WriteStartElement ("root");
  205. w.WriteAttributeString ("type", "object");
  206. w.WriteString ("1");
  207. }
  208. [Test]
  209. [ExpectedException (typeof (XmlException))]
  210. public void WriteArrayNonItem ()
  211. {
  212. w.WriteStartElement ("root");
  213. w.WriteStartElement ("foo");
  214. w.WriteAttributeString ("type", "array");
  215. w.WriteStartElement ("bar");
  216. }
  217. [Test]
  218. public void WriteArray ()
  219. {
  220. w.WriteStartElement ("root"); // name is ignored
  221. w.WriteAttributeString ("type", "array");
  222. w.WriteElementString ("item", "v1");
  223. w.WriteElementString ("item", "v2");
  224. w.Close ();
  225. Assert.AreEqual (@"[""v1"",""v2""]", ResultString, "#1");
  226. }
  227. [Test]
  228. public void WriteArrayInObject ()
  229. {
  230. w.WriteStartElement ("root");
  231. w.WriteAttributeString ("type", "object");
  232. w.WriteStartElement ("foo");
  233. w.WriteAttributeString ("type", "array");
  234. w.WriteElementString ("item", "v1");
  235. w.WriteElementString ("item", "v2");
  236. w.Close ();
  237. Assert.AreEqual (@"{""foo"":[""v1"",""v2""]}", ResultString, "#1");
  238. }
  239. [Test]
  240. [ExpectedException (typeof (ArgumentException))]
  241. public void WriteStartElementNonEmptyNS ()
  242. {
  243. // namespaces are not allowed
  244. w.WriteStartElement (String.Empty, "x", "urn:foo");
  245. }
  246. [Test]
  247. [ExpectedException (typeof (ArgumentException))]
  248. public void WriteStartElementNonEmptyPrefix ()
  249. {
  250. // prefixes are not allowed
  251. w.WriteStartElement ("p", "x", "urn:foo");
  252. }
  253. [Test]
  254. [ExpectedException (typeof (XmlException))]
  255. public void WriteStartElementMultiTopLevel ()
  256. {
  257. w.WriteStartElement ("root");
  258. w.WriteEndElement ();
  259. // hmm...
  260. Assert.AreEqual (WriteState.Content, w.WriteState, "#1");
  261. // writing of multiple root elements is not supported
  262. w.WriteStartElement ("root2");
  263. w.Close ();
  264. Assert.AreEqual (String.Empty, ResultString, "#2");
  265. }
  266. [Test]
  267. [ExpectedException (typeof (ArgumentException))]
  268. public void WriteStartAttributeNonEmptyNS ()
  269. {
  270. // namespaces are not allowed
  271. w.WriteStartElement ("root");
  272. // well, empty prefix for a global attribute would be
  273. // replaced anyways ...
  274. w.WriteStartAttribute (String.Empty, "x", "urn:foo");
  275. }
  276. [Test]
  277. [ExpectedException (typeof (ArgumentException))]
  278. public void WriteStartAttributeInXmlNamespace ()
  279. {
  280. // even "xml" namespace is not allowed (anyways only "type" is allowed ...)
  281. w.WriteStartElement ("root");
  282. w.WriteStartAttribute ("xml", "lang", "http://www.w3.org/XML/1998/namespace");
  283. }
  284. [Test]
  285. [ExpectedException (typeof (ArgumentNullException))]
  286. public void LookupPrefixNull ()
  287. {
  288. w.LookupPrefix (null);
  289. }
  290. [Test]
  291. public void LookupPrefix ()
  292. {
  293. // since namespaces are not allowed, it mostly makes no sense...
  294. Assert.AreEqual (String.Empty, w.LookupPrefix (String.Empty), "#1");
  295. Assert.IsNull (w.LookupPrefix ("urn:nonexistent"), "#2");
  296. Assert.AreEqual ("xml", w.LookupPrefix ("http://www.w3.org/XML/1998/namespace"), "#3");
  297. Assert.AreEqual ("xmlns", w.LookupPrefix ("http://www.w3.org/2000/xmlns/"), "#4");
  298. }
  299. [Test]
  300. public void WriteStartDocument ()
  301. {
  302. Assert.AreEqual (WriteState.Start, w.WriteState, "#1");
  303. w.WriteStartDocument ();
  304. Assert.AreEqual (WriteState.Start, w.WriteState, "#2");
  305. w.WriteStartDocument (true);
  306. Assert.AreEqual (WriteState.Start, w.WriteState, "#3");
  307. // So, it does nothing
  308. }
  309. [Test]
  310. public void WriteEndDocument ()
  311. {
  312. w.WriteEndDocument (); // so, it is completely wrong, but ignored.
  313. }
  314. [Test]
  315. [ExpectedException (typeof (NotSupportedException))]
  316. public void WriteDocType ()
  317. {
  318. w.WriteDocType (null, null, null, null);
  319. }
  320. [Test]
  321. [ExpectedException (typeof (NotSupportedException))]
  322. public void WriteComment ()
  323. {
  324. w.WriteComment ("test");
  325. }
  326. [Test]
  327. [ExpectedException (typeof (NotSupportedException))]
  328. public void WriteEntityRef ()
  329. {
  330. w.WriteEntityRef ("ent");
  331. }
  332. [Test]
  333. [ExpectedException (typeof (ArgumentException))]
  334. public void WriteProcessingInstruction ()
  335. {
  336. // since this method accepts case-insensitive "XML",
  337. // it throws ArgumentException.
  338. w.WriteProcessingInstruction ("T", "D");
  339. }
  340. [Test]
  341. public void WriteProcessingInstructionXML ()
  342. {
  343. // You might not know, but in some cases, things like
  344. // XmlWriter.WriteNode() is implemented to invoke
  345. // this method for writing XML declaration. This
  346. // check is (seems) case-insensitive.
  347. w.WriteProcessingInstruction ("XML", "foobar");
  348. // In this case, the data is simply ignored (as
  349. // WriteStartDocument() is).
  350. }
  351. [Test]
  352. public void WriteRaw ()
  353. {
  354. w.WriteStartElement ("root");
  355. w.WriteRaw ("sample");
  356. w.WriteRaw (new char [] {'0', '1', '2', '3'}, 1, 2);
  357. w.Close ();
  358. Assert.AreEqual ("\"sample12\"", ResultString);
  359. }
  360. [Test]
  361. public void WriteCData ()
  362. {
  363. w.WriteStartElement ("root");
  364. w.WriteCData ("]]>"); // this behavior is incompatible with ordinal XmlWriters.
  365. w.Close ();
  366. Assert.AreEqual ("\"]]>\"", ResultString);
  367. }
  368. [Test]
  369. public void WriteCharEntity ()
  370. {
  371. w.WriteStartElement ("root");
  372. w.WriteCharEntity ('>');
  373. w.Close ();
  374. Assert.AreEqual ("\">\"", ResultString);
  375. }
  376. [Test]
  377. public void WriteWhitespace ()
  378. {
  379. w.WriteStartElement ("root");
  380. w.WriteWhitespace ("\t \n\r");
  381. w.Close ();
  382. Assert.AreEqual (@"""\u0009 \u000a\u000d""", ResultString);
  383. }
  384. [Test]
  385. [ExpectedException (typeof (ArgumentException))]
  386. public void WriteWhitespaceNonWhitespace ()
  387. {
  388. w.WriteStartElement ("root");
  389. w.WriteWhitespace ("TEST");
  390. }
  391. [Test]
  392. [ExpectedException (typeof (InvalidOperationException))]
  393. public void WriteStringTopLevel ()
  394. {
  395. w.WriteString ("test");
  396. }
  397. [Test]
  398. [ExpectedException (typeof (XmlException))]
  399. public void WriteStartAttributeTopLevel ()
  400. {
  401. w.WriteStartAttribute ("test");
  402. }
  403. [Test]
  404. [ExpectedException (typeof (InvalidOperationException))]
  405. public void WriteStartDocumentAtClosed ()
  406. {
  407. w.Close ();
  408. w.WriteStartDocument ();
  409. }
  410. [Test]
  411. [ExpectedException (typeof (InvalidOperationException))]
  412. public void WriteStartElementAtClosed ()
  413. {
  414. w.Close ();
  415. w.WriteStartElement ("foo");
  416. }
  417. [Test]
  418. [ExpectedException (typeof (InvalidOperationException))]
  419. public void WriteProcessingInstructionAtClosed ()
  420. {
  421. w.Close ();
  422. w.WriteProcessingInstruction ("xml", "version='1.0'");
  423. }
  424. [Test]
  425. [ExpectedException (typeof (XmlException))]
  426. public void WriteMixedContent ()
  427. {
  428. w.WriteStartElement ("root");
  429. w.WriteString ("TEST");
  430. w.WriteStartElement ("mixed"); // is not allowed.
  431. }
  432. [Test]
  433. [ExpectedException (typeof (XmlException))]
  434. public void WriteStartElementInvalidTopLevelName ()
  435. {
  436. w.WriteStartElement ("anyname");
  437. }
  438. [Test]
  439. [ExpectedException (typeof (ArgumentNullException))]
  440. public void WriteStartElementNullName ()
  441. {
  442. w.WriteStartElement ("root");
  443. w.WriteAttributeString ("type", "object");
  444. w.WriteStartElement (null);
  445. }
  446. [Test]
  447. [ExpectedException (typeof (ArgumentException))]
  448. public void WriteStartElementEmptyName ()
  449. {
  450. w.WriteStartElement ("root");
  451. w.WriteAttributeString ("type", "object");
  452. w.WriteStartElement (String.Empty);
  453. // It is regarded as invalid name in JSON. However,
  454. // I don't think there is such limitation in JSON specification.
  455. }
  456. [Test]
  457. public void WriteStartElementWithRuntimeTypeName ()
  458. {
  459. w.WriteStartElement ("root");
  460. w.WriteAttributeString ("type", "object");
  461. w.WriteAttributeString ("__type", "FooType:#FooNamespace");
  462. w.Close ();
  463. Assert.AreEqual (@"{""__type"":""FooType:#FooNamespace""}", ResultString);
  464. }
  465. [Test]
  466. public void WriteStartElementWeirdName ()
  467. {
  468. w.WriteStartElement ("root");
  469. w.WriteAttributeString ("type", "object");
  470. w.WriteStartElement ("!!!");
  471. w.Close ();
  472. Assert.AreEqual (@"{""!!!"":""""}", ResultString);
  473. }
  474. [Test]
  475. public void WriteRootAsObject ()
  476. {
  477. w.WriteStartElement ("root");
  478. w.WriteStartAttribute ("type");
  479. w.WriteString ("object");
  480. w.WriteEndAttribute ();
  481. w.Close ();
  482. Assert.AreEqual ("{}", ResultString);
  483. }
  484. [Test]
  485. public void WriteRootAsArray ()
  486. {
  487. w.WriteStartElement ("root");
  488. w.WriteStartAttribute ("type");
  489. w.WriteString ("array");
  490. w.WriteEndAttribute ();
  491. w.Close ();
  492. Assert.AreEqual ("[]", ResultString);
  493. }
  494. [Test]
  495. public void WriteRootAsLiteral ()
  496. {
  497. w.WriteStartElement ("root");
  498. w.Close ();
  499. Assert.AreEqual ("\"\"", ResultString);
  500. }
  501. [Test]
  502. [ExpectedException (typeof (XmlException))]
  503. public void WriteEndElementOnAttribute ()
  504. {
  505. w.WriteStartElement ("root");
  506. w.WriteStartAttribute ("type");
  507. w.WriteString ("array");
  508. w.WriteEndElement ();
  509. }
  510. [Test]
  511. public void WriteAttributeAsSeparateStrings ()
  512. {
  513. w.WriteStartElement ("root");
  514. w.WriteStartAttribute ("type");
  515. w.WriteString ("arr");
  516. w.WriteString ("ay");
  517. w.WriteEndAttribute ();
  518. w.Close ();
  519. Assert.AreEqual ("[]", ResultString);
  520. }
  521. [Test]
  522. [ExpectedException (typeof (XmlException))]
  523. public void WriteStartAttributeInAttributeMode ()
  524. {
  525. w.WriteStartElement ("root");
  526. w.WriteStartAttribute ("type");
  527. w.WriteStartAttribute ("type");
  528. }
  529. [Test]
  530. [ExpectedException (typeof (XmlException))]
  531. public void WriteStartAttributeInContentMode ()
  532. {
  533. w.WriteStartElement ("root");
  534. w.WriteString ("TEST");
  535. w.WriteStartAttribute ("type");
  536. }
  537. [Test]
  538. [ExpectedException (typeof (XmlException))]
  539. public void WriteStartElementInAttributeMode ()
  540. {
  541. w.WriteStartElement ("root");
  542. w.WriteStartAttribute ("type");
  543. w.WriteStartElement ("child");
  544. }
  545. [Test]
  546. [ExpectedException (typeof (XmlException))]
  547. public void CloseAtAtributeState ()
  548. {
  549. w.WriteStartElement ("root");
  550. w.WriteStartAttribute ("type");
  551. w.WriteString ("array");
  552. // It calls WriteEndElement() without calling
  553. // WriteEndAttribute().
  554. w.Close ();
  555. }
  556. [Test]
  557. public void WriteSlashEscaped ()
  558. {
  559. w.WriteStartElement ("root");
  560. w.WriteString ("/my date/");
  561. w.WriteEndElement ();
  562. w.Close ();
  563. Assert.AreEqual ("\"\\/my date\\/\"", ResultString);
  564. }
  565. [Test]
  566. public void WriteNullType ()
  567. {
  568. w.WriteStartElement ("root");
  569. w.WriteAttributeString ("type", "object");
  570. w.WriteStartElement ("foo");
  571. w.WriteAttributeString ("type", "null");
  572. w.Close ();
  573. Assert.AreEqual ("{\"foo\":null}", ResultString);
  574. }
  575. }
  576. }