PageRenderTime 36ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/test/System.Web.Helpers.Test/ObjectInfoTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 728 lines | 525 code | 120 blank | 83 comment | 7 complexity | ecd1c9c3d366b24ff8261a18d5e216c6 MD5 | raw file
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Collections.Specialized;
  4. using System.Dynamic;
  5. using System.Linq;
  6. using System.Web.TestUtil;
  7. using Xunit;
  8. using Assert = Microsoft.TestCommon.AssertEx;
  9. namespace System.Web.Helpers.Test
  10. {
  11. public class ObjectInfoTest
  12. {
  13. [Fact]
  14. public void PrintWithNegativeDepthThrows()
  15. {
  16. // Act & Assert
  17. Assert.ThrowsArgumentGreaterThanOrEqualTo(() => ObjectInfo.Print(null, depth: -1), "depth", "0");
  18. }
  19. [Fact]
  20. public void PrintWithInvalidEnumerationLength()
  21. {
  22. // Act & Assert
  23. Assert.ThrowsArgumentGreaterThan(() => ObjectInfo.Print(null, enumerationLength: -1), "enumerationLength", "0");
  24. }
  25. [Fact]
  26. public void PrintWithNull()
  27. {
  28. // Arrange
  29. MockObjectVisitor visitor = CreateObjectVisitor();
  30. // Act
  31. visitor.Print(null);
  32. // Assert
  33. Assert.Equal(1, visitor.Values.Count);
  34. Assert.Equal("null", visitor.Values[0]);
  35. }
  36. [Fact]
  37. public void PrintWithEmptyString()
  38. {
  39. // Arrange
  40. MockObjectVisitor visitor = CreateObjectVisitor();
  41. // Act
  42. visitor.Print(String.Empty);
  43. // Assert
  44. Assert.Equal(1, visitor.Values.Count);
  45. Assert.Equal(String.Empty, visitor.Values[0]);
  46. }
  47. [Fact]
  48. public void PrintWithInt()
  49. {
  50. // Arrange
  51. MockObjectVisitor visitor = CreateObjectVisitor();
  52. // Act
  53. visitor.Print(404);
  54. // Assert
  55. Assert.Equal(1, visitor.Values.Count);
  56. Assert.Equal("404", visitor.Values[0]);
  57. }
  58. [Fact]
  59. public void PrintWithIDictionary()
  60. {
  61. // Arrange
  62. MockObjectVisitor visitor = CreateObjectVisitor();
  63. IDictionary dict = new OrderedDictionary();
  64. dict.Add("foo", "bar");
  65. dict.Add("abc", 500);
  66. // Act
  67. visitor.Print(dict);
  68. // Assert
  69. Assert.Equal("foo = bar", visitor.KeyValuePairs[0]);
  70. Assert.Equal("abc = 500", visitor.KeyValuePairs[1]);
  71. }
  72. [Fact]
  73. public void PrintWithIEnumerable()
  74. {
  75. // Arrange
  76. MockObjectVisitor visitor = CreateObjectVisitor();
  77. var values = Enumerable.Range(0, 10);
  78. // Act
  79. visitor.Print(values);
  80. // Assert
  81. foreach (var num in values)
  82. {
  83. Assert.True(visitor.Values.Contains(num.ToString()));
  84. }
  85. }
  86. [Fact]
  87. public void PrintWithGenericIListPrintsIndex()
  88. {
  89. // Arrange
  90. MockObjectVisitor visitor = CreateObjectVisitor();
  91. var values = Enumerable.Range(0, 10).ToList();
  92. // Act
  93. visitor.Print(values);
  94. // Assert
  95. for (int i = 0; i < values.Count; i++)
  96. {
  97. Assert.True(visitor.Values.Contains(values[i].ToString()));
  98. Assert.True(visitor.Indexes.Contains(i));
  99. }
  100. }
  101. [Fact]
  102. public void PrintWithArrayPrintsIndex()
  103. {
  104. // Arrange
  105. MockObjectVisitor visitor = CreateObjectVisitor();
  106. var values = Enumerable.Range(0, 10).ToArray();
  107. // Act
  108. visitor.Print(values);
  109. // Assert
  110. for (int i = 0; i < values.Length; i++)
  111. {
  112. Assert.True(visitor.Values.Contains(values[i].ToString()));
  113. Assert.True(visitor.Indexes.Contains(i));
  114. }
  115. }
  116. [Fact]
  117. public void PrintNameValueCollectionPrintsKeysAndValues()
  118. {
  119. // Arrange
  120. MockObjectVisitor visitor = CreateObjectVisitor();
  121. var values = new NameValueCollection();
  122. values["a"] = "1";
  123. values["b"] = null;
  124. // Act
  125. visitor.Print(values);
  126. // Assert
  127. Assert.Equal("a = 1", visitor.KeyValuePairs[0]);
  128. Assert.Equal("b = null", visitor.KeyValuePairs[1]);
  129. }
  130. [Fact]
  131. public void PrintDateTime()
  132. {
  133. using (new CultureReplacer())
  134. {
  135. // Arrange
  136. MockObjectVisitor visitor = CreateObjectVisitor();
  137. var dt = new DateTime(2001, 11, 20, 10, 30, 1);
  138. // Act
  139. visitor.Print(dt);
  140. // Assert
  141. Assert.Equal("11/20/2001 10:30:01 AM", visitor.Values[0]);
  142. }
  143. }
  144. [Fact]
  145. public void PrintCustomObjectPrintsMembers()
  146. {
  147. // Arrange
  148. MockObjectVisitor visitor = CreateObjectVisitor();
  149. var person = new Person
  150. {
  151. Name = "David",
  152. Age = 23.3,
  153. Dob = new DateTime(1986, 11, 19),
  154. LongType = 1000000000,
  155. Type = 1
  156. };
  157. using (new CultureReplacer())
  158. {
  159. // Act
  160. visitor.Print(person);
  161. // Assert
  162. Assert.Equal(9, visitor.Members.Count);
  163. Assert.True(visitor.Members.Contains("double Age = 23.3"));
  164. Assert.True(visitor.Members.Contains("string Name = David"));
  165. Assert.True(visitor.Members.Contains("DateTime Dob = 11/19/1986 12:00:00 AM"));
  166. Assert.True(visitor.Members.Contains("short Type = 1"));
  167. Assert.True(visitor.Members.Contains("float Float = 0"));
  168. Assert.True(visitor.Members.Contains("byte Byte = 0"));
  169. Assert.True(visitor.Members.Contains("decimal Decimal = 0"));
  170. Assert.True(visitor.Members.Contains("bool Bool = False"));
  171. }
  172. }
  173. [Fact]
  174. public void PrintShowsVisitedWhenCircularReferenceInObjectGraph()
  175. {
  176. // Arrange
  177. MockObjectVisitor visitor = CreateObjectVisitor();
  178. PersonNode node = new PersonNode
  179. {
  180. Person = new Person
  181. {
  182. Name = "David",
  183. Age = 23.3
  184. }
  185. };
  186. node.Next = node;
  187. // Act
  188. visitor.Print(node);
  189. // Assert
  190. Assert.True(visitor.Members.Contains("string Name = David"));
  191. Assert.True(visitor.Members.Contains("double Age = 23.3"));
  192. Assert.True(visitor.Members.Contains("PersonNode Next = Visited"));
  193. }
  194. [Fact]
  195. public void PrintShowsVisitedWhenCircularReferenceIsIEnumerable()
  196. {
  197. // Arrange
  198. MockObjectVisitor visitor = CreateObjectVisitor();
  199. List<object> values = new List<object>();
  200. values.Add(values);
  201. // Act
  202. visitor.Print(values);
  203. // Assert
  204. Assert.Equal("Visited", visitor.Values[0]);
  205. Assert.Equal("Visited " + values.GetHashCode(), visitor.Visited[0]);
  206. }
  207. [Fact]
  208. public void PrintShowsVisitedWhenCircularReferenceIsIDictionary()
  209. {
  210. // Arrange
  211. MockObjectVisitor visitor = CreateObjectVisitor();
  212. OrderedDictionary values = new OrderedDictionary();
  213. values[values] = values;
  214. // Act
  215. visitor.Print(values);
  216. // Assert
  217. Assert.Equal("Visited", visitor.Values[0]);
  218. Assert.Equal("Visited " + values.GetHashCode(), visitor.Visited[0]);
  219. }
  220. [Fact]
  221. public void PrintShowsVisitedWhenCircularReferenceIsNameValueCollection()
  222. {
  223. // Arrange
  224. MockObjectVisitor visitor = CreateObjectVisitor();
  225. NameValueCollection nameValues = new NameValueCollection();
  226. nameValues["id"] = "1";
  227. List<NameValueCollection> values = new List<NameValueCollection>();
  228. values.Add(nameValues);
  229. values.Add(nameValues);
  230. // Act
  231. visitor.Print(values);
  232. // Assert
  233. Assert.True(visitor.Values.Contains("Visited"));
  234. Assert.True(visitor.Visited.Contains("Visited " + nameValues.GetHashCode()));
  235. }
  236. [Fact]
  237. public void PrintExcludesWriteOnlyProperties()
  238. {
  239. // Arrange
  240. MockObjectVisitor visitor = CreateObjectVisitor();
  241. ClassWithWriteOnlyProperty cls = new ClassWithWriteOnlyProperty();
  242. // Act
  243. visitor.Print(cls);
  244. // Assert
  245. Assert.Equal(0, visitor.Members.Count);
  246. }
  247. [Fact]
  248. public void PrintWritesEnumeratedElementsUntilLimitIsHit()
  249. {
  250. // Arrange
  251. MockObjectVisitor visitor = CreateObjectVisitor();
  252. var enumeration = Enumerable.Range(0, 2000);
  253. // Act
  254. visitor.Print(enumeration);
  255. // Assert
  256. for (int i = 0; i <= 2000; i++)
  257. {
  258. if (i < 1000)
  259. {
  260. Assert.True(visitor.Values.Contains(i.ToString()));
  261. }
  262. else
  263. {
  264. Assert.False(visitor.Values.Contains(i.ToString()));
  265. }
  266. }
  267. Assert.True(visitor.Values.Contains("Limit Exceeded"));
  268. }
  269. [Fact]
  270. public void PrintWithAnonymousType()
  271. {
  272. // Arrange
  273. MockObjectVisitor visitor = CreateObjectVisitor();
  274. var value = new { Name = "John", X = 1 };
  275. // Act
  276. visitor.Print(value);
  277. // Assert
  278. Assert.True(visitor.Members.Contains("string Name = John"));
  279. Assert.True(visitor.Members.Contains("int X = 1"));
  280. }
  281. [Fact]
  282. public void PrintClassWithPublicFields()
  283. {
  284. // Arrange
  285. MockObjectVisitor visitor = CreateObjectVisitor();
  286. ClassWithFields value = new ClassWithFields();
  287. value.Foo = "John";
  288. value.Bar = 1;
  289. // Actt
  290. visitor.Print(value);
  291. // Assert
  292. Assert.True(visitor.Members.Contains("string Foo = John"));
  293. Assert.True(visitor.Members.Contains("int Bar = 1"));
  294. }
  295. [Fact]
  296. public void PrintClassWithDynamicMembersPrintsMembersIfGetDynamicMemberNamesIsImplemented()
  297. {
  298. // Arrange
  299. MockObjectVisitor visitor = CreateObjectVisitor();
  300. dynamic d = new DynamicDictionary();
  301. d.Cycle = d;
  302. d.Name = "Foo";
  303. d.Value = null;
  304. // Act
  305. visitor.Print(d);
  306. // Assert
  307. Assert.True(visitor.Members.Contains("DynamicDictionary Cycle = Visited"));
  308. Assert.True(visitor.Members.Contains("string Name = Foo"));
  309. Assert.True(visitor.Members.Contains("Value = null"));
  310. }
  311. [Fact]
  312. public void PrintClassWithDynamicMembersReturningNullPrintsNoMembers()
  313. {
  314. // Arrange
  315. MockObjectVisitor visitor = CreateObjectVisitor();
  316. dynamic d = new ClassWithDynamicAnNullMemberNames();
  317. d.Cycle = d;
  318. d.Name = "Foo";
  319. d.Value = null;
  320. // Act
  321. visitor.Print(d);
  322. // Assert
  323. Assert.False(visitor.Members.Any());
  324. }
  325. [Fact]
  326. public void PrintUsesToStringOfIConvertibleObjects()
  327. {
  328. // Arrange
  329. MockObjectVisitor visitor = CreateObjectVisitor();
  330. ConvertibleClass cls = new ConvertibleClass();
  331. // Act
  332. visitor.Print(cls);
  333. // Assert
  334. Assert.Equal("Test", visitor.Values[0]);
  335. }
  336. [Fact]
  337. public void PrintConvertsTypeToString()
  338. {
  339. // Arrange
  340. MockObjectVisitor visitor = CreateObjectVisitor();
  341. // Act
  342. visitor.Print(typeof(string));
  343. // Assert
  344. Assert.Equal("typeof(string)", visitor.Values[0]);
  345. }
  346. [Fact]
  347. public void PrintClassWithPropertyThatThrowsExceptionPrintsException()
  348. {
  349. // Arrange
  350. MockObjectVisitor visitor = CreateObjectVisitor();
  351. ClassWithPropertyThatThrowsException value = new ClassWithPropertyThatThrowsException();
  352. // Act
  353. visitor.Print(value);
  354. // Assert
  355. Assert.Equal("int MyProperty = Property accessor 'MyProperty' on object 'System.Web.Helpers.Test.ObjectInfoTest+ClassWithPropertyThatThrowsException' threw the following exception:'Property that shows an exception'", visitor.Members[0]);
  356. }
  357. [Fact]
  358. public void ConvertEscapeSequencesPrintsStringEscapeSequencesAsLiterals()
  359. {
  360. // Act
  361. string value = HtmlObjectPrinter.ConvertEscapseSequences("\\\'\"\0\a\b\f\n\r\t\v");
  362. // Assert
  363. Assert.Equal("\\\\'\\\"\\0\\a\\b\\f\\n\\r\\t\\v", value);
  364. }
  365. [Fact]
  366. public void ConvertEscapeSequencesDoesNotEscapeUnicodeSequences()
  367. {
  368. // Act
  369. string value = HtmlObjectPrinter.ConvertEscapseSequences("\u1023\x2045");
  370. // Assert
  371. Assert.Equal("\u1023\x2045", value);
  372. }
  373. [Fact]
  374. public void PrintCharPrintsQuotedString()
  375. {
  376. // Arrange
  377. HtmlObjectPrinter printer = new HtmlObjectPrinter(100, 100);
  378. HtmlElement element = new HtmlElement("span");
  379. printer.PushElement(element);
  380. // Act
  381. printer.VisitConvertedValue('x', "x");
  382. // Assert
  383. Assert.Equal(1, element.Children.Count);
  384. HtmlElement child = element.Children[0];
  385. Assert.Equal("'x'", child.InnerText);
  386. Assert.Equal("quote", child["class"]);
  387. }
  388. [Fact]
  389. public void PrintEscapeCharPrintsEscapedCharAsLiteral()
  390. {
  391. // Arrange
  392. HtmlObjectPrinter printer = new HtmlObjectPrinter(100, 100);
  393. HtmlElement element = new HtmlElement("span");
  394. printer.PushElement(element);
  395. // Act
  396. printer.VisitConvertedValue('\t', "\t");
  397. // Assert
  398. Assert.Equal(1, element.Children.Count);
  399. HtmlElement child = element.Children[0];
  400. Assert.Equal("'\\t'", child.InnerText);
  401. Assert.Equal("quote", child["class"]);
  402. }
  403. [Fact]
  404. public void GetTypeNameConvertsGenericTypesToCsharpSyntax()
  405. {
  406. // Act
  407. string value = ObjectVisitor.GetTypeName(typeof(Func<Func<Func<int, int, object>, Action<int>>>));
  408. // Assert
  409. Assert.Equal("Func<Func<Func<int, int, object>, Action<int>>>", value);
  410. }
  411. private class ConvertibleClass : IConvertible
  412. {
  413. public TypeCode GetTypeCode()
  414. {
  415. throw new NotImplementedException();
  416. }
  417. public bool ToBoolean(IFormatProvider provider)
  418. {
  419. throw new NotImplementedException();
  420. }
  421. public byte ToByte(IFormatProvider provider)
  422. {
  423. throw new NotImplementedException();
  424. }
  425. public char ToChar(IFormatProvider provider)
  426. {
  427. throw new NotImplementedException();
  428. }
  429. public DateTime ToDateTime(IFormatProvider provider)
  430. {
  431. throw new NotImplementedException();
  432. }
  433. public decimal ToDecimal(IFormatProvider provider)
  434. {
  435. throw new NotImplementedException();
  436. }
  437. public double ToDouble(IFormatProvider provider)
  438. {
  439. throw new NotImplementedException();
  440. }
  441. public short ToInt16(IFormatProvider provider)
  442. {
  443. throw new NotImplementedException();
  444. }
  445. public int ToInt32(IFormatProvider provider)
  446. {
  447. throw new NotImplementedException();
  448. }
  449. public long ToInt64(IFormatProvider provider)
  450. {
  451. throw new NotImplementedException();
  452. }
  453. public sbyte ToSByte(IFormatProvider provider)
  454. {
  455. throw new NotImplementedException();
  456. }
  457. public float ToSingle(IFormatProvider provider)
  458. {
  459. throw new NotImplementedException();
  460. }
  461. public string ToString(IFormatProvider provider)
  462. {
  463. return "Test";
  464. }
  465. public object ToType(Type conversionType, IFormatProvider provider)
  466. {
  467. throw new NotImplementedException();
  468. }
  469. public ushort ToUInt16(IFormatProvider provider)
  470. {
  471. throw new NotImplementedException();
  472. }
  473. public uint ToUInt32(IFormatProvider provider)
  474. {
  475. throw new NotImplementedException();
  476. }
  477. public ulong ToUInt64(IFormatProvider provider)
  478. {
  479. throw new NotImplementedException();
  480. }
  481. }
  482. private class ClassWithPropertyThatThrowsException
  483. {
  484. public int MyProperty
  485. {
  486. get { throw new InvalidOperationException("Property that shows an exception"); }
  487. }
  488. }
  489. private class ClassWithDynamicAnNullMemberNames : DynamicObject
  490. {
  491. public override IEnumerable<string> GetDynamicMemberNames()
  492. {
  493. return null;
  494. }
  495. public override bool TryGetMember(GetMemberBinder binder, out object result)
  496. {
  497. result = null;
  498. return true;
  499. }
  500. public override bool TrySetMember(SetMemberBinder binder, object value)
  501. {
  502. return true;
  503. }
  504. }
  505. private class Person
  506. {
  507. public string Name { get; set; }
  508. public double Age { get; set; }
  509. public DateTime Dob { get; set; }
  510. public short Type { get; set; }
  511. public long LongType { get; set; }
  512. public float Float { get; set; }
  513. public byte Byte { get; set; }
  514. public decimal Decimal { get; set; }
  515. public bool Bool { get; set; }
  516. }
  517. private class ClassWithFields
  518. {
  519. public string Foo;
  520. public int Bar = 13;
  521. }
  522. private class ClassWithWriteOnlyProperty
  523. {
  524. public int Value
  525. {
  526. set { }
  527. }
  528. }
  529. private class PersonNode
  530. {
  531. public Person Person { get; set; }
  532. public PersonNode Next { get; set; }
  533. }
  534. private MockObjectVisitor CreateObjectVisitor(int recursionLimit = 10, int enumerationLimit = 1000)
  535. {
  536. return new MockObjectVisitor(recursionLimit, enumerationLimit);
  537. }
  538. private class MockObjectVisitor : ObjectVisitor
  539. {
  540. public MockObjectVisitor(int recursionLimit, int enumerationLimit)
  541. : base(recursionLimit, enumerationLimit)
  542. {
  543. Values = new List<string>();
  544. KeyValuePairs = new List<string>();
  545. Members = new List<string>();
  546. Indexes = new List<int>();
  547. Visited = new List<string>();
  548. }
  549. public List<string> Values { get; set; }
  550. public List<string> KeyValuePairs { get; set; }
  551. public List<string> Members { get; set; }
  552. public List<int> Indexes { get; set; }
  553. public List<string> Visited { get; set; }
  554. public void Print(object value)
  555. {
  556. Visit(value, 0);
  557. }
  558. public override void VisitObjectVisitorException(ObjectVisitorException exception)
  559. {
  560. Values.Add(exception.InnerException.Message);
  561. }
  562. public override void VisitStringValue(string stringValue)
  563. {
  564. Values.Add(stringValue);
  565. base.VisitStringValue(stringValue);
  566. }
  567. public override void VisitVisitedObject(string id, object value)
  568. {
  569. Visited.Add(String.Format("Visited {0}", id));
  570. Values.Add("Visited");
  571. base.VisitVisitedObject(id, value);
  572. }
  573. public override void VisitIndexedEnumeratedValue(int index, object item, int depth)
  574. {
  575. Indexes.Add(index);
  576. base.VisitIndexedEnumeratedValue(index, item, depth);
  577. }
  578. public override void VisitEnumeratonLimitExceeded()
  579. {
  580. Values.Add("Limit Exceeded");
  581. base.VisitEnumeratonLimitExceeded();
  582. }
  583. public override void VisitMember(string name, Type type, object value, int depth)
  584. {
  585. base.VisitMember(name, type, value, depth);
  586. type = type ?? (value != null ? value.GetType() : null);
  587. if (type == null)
  588. {
  589. Members.Add(String.Format("{0} = null", name));
  590. }
  591. else
  592. {
  593. Members.Add(String.Format("{0} {1} = {2}", GetTypeName(type), name, Values.Last()));
  594. }
  595. }
  596. public override void VisitNull()
  597. {
  598. Values.Add("null");
  599. base.VisitNull();
  600. }
  601. public override void VisitKeyValue(object key, object value, int depth)
  602. {
  603. base.VisitKeyValue(key, value, depth);
  604. KeyValuePairs.Add(String.Format("{0} = {1}", Values[Values.Count - 2], Values[Values.Count - 1]));
  605. }
  606. }
  607. }
  608. }