From 67f56f0795ac0214f9828c42f8face229e204c1d Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 21 Feb 2009 06:55:20 +0000 Subject: ClojureCLR: added ClojureCLR project to repo. --- .../Clojure/Clojure.Tests/LibTests/AFnImplTests.cs | 22 + .../LibTests/APersistentVectorTests.cs | 707 ++++++++ .../Clojure/Clojure.Tests/LibTests/ARefTests.cs | 22 + .../Clojure.Tests/LibTests/AReferenceTests.cs | 98 ++ .../Clojure/Clojure.Tests/LibTests/AgentTests.cs | 22 + .../Clojure.Tests/LibTests/ArraySeqTests.cs | 214 +++ .../Clojure.Tests/LibTests/ArrayStreamTests.cs | 22 + .../Clojure/Clojure.Tests/LibTests/AtomTests.cs | 22 + .../Clojure.Tests/LibTests/CachedSeqTests.cs | 22 + .../Clojure/Clojure.Tests/LibTests/ConsTests.cs | 428 +++++ .../Clojure/Clojure.Tests/LibTests/DelayTests.cs | 22 + .../Clojure/Clojure.Tests/LibTests/FnSeqTests.cs | 120 ++ .../Clojure/Clojure.Tests/LibTests/IObjTests.cs | 91 + .../Clojure.Tests/LibTests/ISeqTestHelper.cs | 54 + .../Clojure.Tests/LibTests/IteratorStreamTests.cs | 22 + .../Clojure/Clojure.Tests/LibTests/KeywordTests.cs | 239 +++ .../LibTests/LazilyPersistentVectorTests.cs | 220 +++ .../Clojure.Tests/LibTests/LazyConsTests.cs | 123 ++ .../Clojure.Tests/LibTests/LispReaderTests.cs | 1789 ++++++++++++++++++++ .../LibTests/LockingTransactionTests.cs | 194 +++ .../Clojure.Tests/LibTests/MapEntryTests.cs | 369 ++++ .../Clojure.Tests/LibTests/NamespaceTests.cs | 257 +++ .../Clojure/Clojure.Tests/LibTests/NumbersTests.cs | 137 ++ .../Clojure/Clojure.Tests/LibTests/ObjTests.cs | 68 + .../LibTests/PersistentArrayMapTests.cs | 917 ++++++++++ .../LibTests/PersistentHashMapTests.cs | 242 +++ .../LibTests/PersistentHashSetTests.cs | 188 ++ .../Clojure.Tests/LibTests/PersistentListTests.cs | 245 +++ .../Clojure.Tests/LibTests/PersistentQueueTests.cs | 22 + .../LibTests/PersistentStructMapTests.cs | 22 + .../LibTests/PersistentTreeMapTests.cs | 233 +++ .../LibTests/PersistentTreeSetTests.cs | 58 + .../LibTests/PersistentVectorTests.cs | 330 ++++ .../Clojure/Clojure.Tests/LibTests/RangeTests.cs | 182 ++ .../Clojure/Clojure.Tests/LibTests/RefTests.cs | 23 + .../Clojure.Tests/LibTests/RestFnImplTests.cs | 22 + .../Clojure/Clojure.Tests/LibTests/RestFnTests.cs | 22 + .../Clojure.Tests/LibTests/StreamSeqTests.cs | 22 + .../Clojure.Tests/LibTests/StringSeqTests.cs | 163 ++ .../Clojure/Clojure.Tests/LibTests/SymbolTests.cs | 326 ++++ .../Clojure/Clojure.Tests/LibTests/TestTest.cs | 62 + 41 files changed, 8363 insertions(+) create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/AFnImplTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/APersistentVectorTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/ARefTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/AReferenceTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/AgentTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/ArraySeqTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/ArrayStreamTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/AtomTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/CachedSeqTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/ConsTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/DelayTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/FnSeqTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/IObjTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/ISeqTestHelper.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/IteratorStreamTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/KeywordTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/LazilyPersistentVectorTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/LazyConsTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/LispReaderTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/LockingTransactionTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/MapEntryTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/NamespaceTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/NumbersTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/ObjTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentArrayMapTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentHashMapTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentHashSetTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentListTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentQueueTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentStructMapTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentTreeMapTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentTreeSetTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentVectorTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/RangeTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/RefTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/RestFnImplTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/RestFnTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/StreamSeqTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/StringSeqTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/SymbolTests.cs create mode 100644 ClojureCLR/Clojure/Clojure.Tests/LibTests/TestTest.cs (limited to 'ClojureCLR/Clojure/Clojure.Tests/LibTests') diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/AFnImplTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/AFnImplTests.cs new file mode 100644 index 00000000..3c79b69b --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/AFnImplTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add AFnImpl tests + class AFnImplTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/APersistentVectorTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/APersistentVectorTests.cs new file mode 100644 index 00000000..88213a02 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/APersistentVectorTests.cs @@ -0,0 +1,707 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + + +namespace Clojure.Tests.LibTests +{ + + // TODO: Add tests for APersistentVector.SubVector + // TODO: Add tests for APersistentVector.stream + + [TestFixture] + public class APersistentVectorTests : AssertionHelper + { + + // Usually, we test the abstract classes via the simplest concrete class that derives from it. + // For APersistentVector, all the concrete classes are fairly complicated. + // Hence we create a test concrete implementation class. + // This class has no guarantees of persistence/immutability, thread-safety, + // or much of anything else, certainly not efficiency. + // We determined the methods to override by trying to compile the class with no methods. + // Thus, we have implemented only the absolute minimum. + // We will write tests for these methods, too. + // This class just has an underlying List to hold values. + class CPV : APersistentVector + { + object[] _values; + + public CPV(object[] values) + : base(null) + { + _values = values; + } + + + public CPV(IPersistentMap meta, object[] values) + : base(meta) + { + _values = values; + } + + public override IObj withMeta(IPersistentMap meta) + { + return meta == _meta + ? this + : new CPV(meta, _values); + } + + //public override object applyTo(ISeq arglist) + //{ + // throw new NotImplementedException(); + //} + + public override IPersistentStack pop() + { + if (_values.Length == 0) + throw new InvalidOperationException("Can't pop a null stack."); + + object[] newArr = new object[_values.Length - 1]; + Array.Copy(_values, newArr, _values.Length - 1); + + return new CPV(_meta, newArr); + } + + public override IPersistentVector cons(object o) + { + object[] newArr = new object[_values.Length + 1]; + _values.CopyTo(newArr, 0); + newArr[_values.Length] = o; + return new CPV(_meta, newArr); + } + + public override IPersistentVector assocN(int i, object val) + { + if ( 0 <= i && i < _values.Length ) + { + object[] newArr = new object[_values.Length]; + _values.CopyTo(newArr, 0); + newArr[i] = val; + return new CPV(_meta, newArr); + } + if ( i == _values.Length ) + return cons(val); + throw new IndexOutOfRangeException(); + } + + public override object nth(int i) + { + return _values[i]; + } + + public override int length() + { + return _values.Length; + } + + private static CPV EMPTY = new CPV(new object[0]); + public override IPersistentCollection empty() + { + return EMPTY; + } + + public override int count() + { + return _values.Length; + } + } + + #region C-tor tests + + [Test] + public void NoMetaCtorHasNoMeta() + { + CPV v = new CPV(new object[] { 1, 2, 3 }); + + Expect(v.meta(),Null); + } + + [Test] + public void MetaCtorHasMeta() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + CPV v = new CPV(meta,new object[] { 1, 2, 3 }); + + Expect(v.meta(), SameAs(meta)); + mocks.VerifyAll(); + } + + #endregion + + #region Object tests + + [Test] + public void ToStringMentionsTheCount() + { + CPV v = new CPV(new object[] { 1, 2, 3 }); + string str = v.ToString(); + + Expect(str.Contains("3")); + } + + [Test] + public void HashCodeRepeats() + { + CPV v = new CPV(new object[] { 1, 2, 3 }); + + Expect(v.GetHashCode(), EqualTo(v.GetHashCode())); + } + + [Test] + public void HashCodeDependsOnItems() + { + CPV v1 = new CPV(new object[] { 1, 2, 3 }); + CPV v2 = new CPV(new object[] { 1, 2, 4 }); + + Expect(v1.GetHashCode(), Not.EqualTo(v2.GetHashCode())); + } + + [Test] + public void EqualsOnNonPersistentVectorIsFalse() + { + CPV v1 = new CPV(new object[] { 1, 2, 3 }); + + Expect(v1.equiv(7), False); + } + + [Test] + public void EqualsOnPersistentVectorWithDifferentItemsIsFalse() + { + CPV v1 = new CPV(new object[] { 1, 2, 3 }); + CPV v2 = new CPV(new object[] { 1, 2, 4 }); + CPV v3 = new CPV(new object[] { 1, 2 }); + CPV v4 = new CPV(new object[] { 1, 2, 3, 4 }); + + Expect(v1.equiv(v2), False); + Expect(v1.equiv(v3), False); + Expect(v1.equiv(v4), False); + } + + [Test] + public void EqualsOnPersistentVectorWithSameItemsIsTrue() + { + CPV v1 = new CPV(new object[] { 1, 2, 3 }); + CPV v2 = new CPV(new object[] { 1, 2, 3 }); + CPV v3 = new CPV(new object[] { 1 }); + CPV v4 = new CPV(new object[] { 1 }); + CPV v5 = new CPV(new object[] { }); + CPV v6 = new CPV(new object[] { }); + + Expect(v1.equiv(v2)); + Expect(v3.equiv(v4)); + Expect(v5.equiv(v6)); + } + + [Test] + public void EqualsOnSimilarISeqWorks() + { + CPV v1 = new CPV(new object[] { 'a', 'b', 'c' }); + StringSeq s1 = StringSeq.create("abc"); + + Expect(v1.equiv(s1)); + } + + [Test] + public void EqualsOnDissimilarISeqFails() + { + CPV v1 = new CPV(new object[] { 'a', 'b', 'c' }); + StringSeq s1 = StringSeq.create("ab"); + StringSeq s2 = StringSeq.create("abd"); + StringSeq s3 = StringSeq.create("abcd"); + + Expect(v1.equiv(s1), False); + Expect(v1.equiv(s2), False); + Expect(v1.equiv(s3), False); + } + + + #endregion + + #region IFn tests + + [Test] + public void InvokeCallsNth() + { + CPV v = new CPV(new object[] { 5, 6, 7 }); + + Expect(v.invoke(0),EqualTo(5)); + Expect(v.invoke(1),EqualTo(6)); + Expect(v.invoke(2),EqualTo(7)); + Expect(v.invoke("1"), EqualTo(6)); + Expect(v.invoke(1.0), EqualTo(6)); + Expect(v.invoke(1.2), EqualTo(6)); + Expect(v.invoke(1.8), EqualTo(6)); // Rounds or not-- should it? + Expect(v.invoke(1.4M), EqualTo(6)); + } + + + #endregion + + #region IPersistentCollection tests + + [Test] + public void SeqOnCount0YieldsNull() + { + CPV v = new CPV(new object[0]); + + Expect(v.seq(), Null); + } + + [Test] + public void SeqOnPositiveCountYieldsNotNull() + { + CPV v = new CPV(new object[]{ 1,2,3}); + + Expect(v.seq(), Not.Null); + } + + [Test] + public void SeqOnPositiveCountYieldsValidSequence() + { + CPV v = new CPV(new object[] { 1, 2, 3 }); + ISeq s = v.seq(); + + Expect(s.first(), EqualTo(1)); + Expect(s.rest().first(), EqualTo(2)); + Expect(s.rest().rest().first(), EqualTo(3)); + Expect(s.rest().rest().rest(), Null); + } + + [Test] + public void Explicit_IPersistentCollection_cons_works() + { + CPV v = new CPV(new object[] { 1, 2 }); + IPersistentCollection c = v as IPersistentCollection; + + Expect(c, Not.Null); + + IPersistentCollection c2 = c.cons(3); + Expect(c2.count(), EqualTo(3)); + + ISeq s2 = c2.seq(); + + Expect(s2.first(), EqualTo(1)); + Expect(s2.rest().first(), EqualTo(2)); + Expect(s2.rest().rest().first(), EqualTo(3)); + Expect(s2.rest().rest().rest(), Null); + } + + #endregion + + #region Reversible tests + + [Test] + public void RseqOnCount0YieldsNull() + { + CPV v = new CPV(new object[0]); + + Expect(v.rseq(), Null); + } + + [Test] + public void RSeqOnPositiveCountYieldsNotNull() + { + CPV v = new CPV(new object[] { 1, 2, 3 }); + + Expect(v.rseq(), Not.Null); + } + + [Test] + public void RseqOnPositiveCountYieldsValidSequence() + { + CPV v = new CPV(new object[] { 1, 2, 3 }); + ISeq s = v.rseq(); + + Expect(s.first(), EqualTo(3)); + Expect(s.rest().first(), EqualTo(2)); + Expect(s.rest().rest().first(), EqualTo(1)); + Expect(s.rest().rest().rest(), Null); + } + + + #endregion + + #region Associative tests + + [Test] + public void ContainsKeyOnNonNumericIsFalse() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + + Expect(v.containsKey("a"), False); + } + + [Test] + public void ContainsKeyOnIndexInRangeIsTrue() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + + Expect(v.containsKey(1.2)); + } + + + [Test] + public void ContainsKeyOnIndexOutOfRangeIsFalse() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + + Expect(v.containsKey(5),False); + } + + [Test] + public void EntryAtOnNonNumericReturnsNull() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + + IMapEntry me = v.entryAt("a"); + + Expect(me, Null); + } + + [Test] + public void EntryAtOnIndexInRangeReturnsEntry() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + + IMapEntry me = v.entryAt(1); + + Expect(me.key(), EqualTo(1)); + Expect(me.val(),EqualTo(5)); + } + + + [Test] + public void EntryAtOnIndexOutOfRangeReturnsNull() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + + IMapEntry me = v.entryAt(5); + + Expect(me, Null); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void AssocWithNonNumericKeyThrowsException() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + Associative a = v.assoc("a", 7); + } + + [Test] + public void AssocWithNumericKeyInRangeChangesValue() + { + //This just checks that APersistentVector.assoc calls CPV.assocN + CPV v = new CPV(new object[] { 4, 5, 6 }); + Associative a = v.assoc(1, 10); + + Expect(a.valAt(0), EqualTo(4)); + Expect(a.valAt(1), EqualTo(10)); + Expect(a.valAt(2), EqualTo(6)); + Expect(a.count(), EqualTo(3)); + } + + [Test] + public void AssocWithNumericKeyOnePastEndAddValue() + { + //This just checks that APersistentVector.assoc calls CPV.assocN + CPV v = new CPV(new object[] { 4, 5, 6 }); + Associative a = v.assoc(3, 10); + + Expect(a.valAt(0), EqualTo(4)); + Expect(a.valAt(1), EqualTo(5)); + Expect(a.valAt(2), EqualTo(6)); + Expect(a.valAt(3), EqualTo(10)); + Expect(a.count(), EqualTo(4)); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void AssocWithNumericKeyOutOfRangeHighThrowsException() + { + //This just checks that APersistentVector.assoc calls CPV.assocN + CPV v = new CPV(new object[] { 4, 5, 6 }); + Associative a = v.assoc(4, 10); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void AssocWithNumericKeyOutOfRangeLowThrowsException() + { + //This just checks that APersistentVector.assoc calls CPV.assocN + CPV v = new CPV(new object[] { 4, 5, 6 }); + Associative a = v.assoc(-1, 10); + } + + [Test] + public void ValAtOnNonNumericReturnsDefault() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + + object val1 = v.valAt("a"); + object val2 = v.valAt("a", "abc"); + + Expect(val1, Null); + Expect(val2, EqualTo("abc")); + } + + [Test] + public void ValAtOnIndexInRangeReturnsEntry() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + + object val1 = v.valAt(1); + object val2 = v.valAt(1, "abc"); + + Expect(val1, EqualTo(5)); + Expect(val2, EqualTo(5)); + } + + + [Test] + public void ValAtOnIndexOutOfRangeReturnsDefault() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + + IMapEntry me = v.entryAt(5); + + object val1 = v.valAt(4); + object val2 = v.valAt(4, "abc"); + + Expect(val1, Null); + Expect(val2, EqualTo("abc")); + } + + + + #endregion + + #region IPersistentStack tests + + [Test] + public void PeekOnCount0ReturnsNull() + { + CPV v = new CPV(new object[] {}); + + Expect(v.peek(), Null); + } + + [Test] + public void PeekOnPositiveCountReturnsLastItem() + { + CPV v = new CPV(new object[] { 1, 2, 3 }); + + Expect(v.peek(), EqualTo(3)); + } + + #endregion + + #region APersistentVector.Seq tests + + // We'll do all the tests indirectly. + + [Test] + public void SeqFirstAndRestWork() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + ISeq s = v.seq(); + + Expect(s.first(), EqualTo(4)); + Expect(s.rest().first(), EqualTo(5)); + Expect(s.rest().rest().first(), EqualTo(6)); + Expect(s.rest().rest().rest(), Null); + } + + [Test] + public void SeqIndexedWorks() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + ISeq s0 = v.seq(); + IndexedSeq i0 = s0 as IndexedSeq; + + ISeq s1 = s0.rest(); + IndexedSeq i1 = s1 as IndexedSeq; + + Expect(i0.index(), EqualTo(0)); + Expect(i1.index(), EqualTo(1)); + } + + [Test] + public void SeqCountWorks() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + ISeq s = v.seq(); + + Expect(s.count(), EqualTo(3)); + Expect(s.rest().count(), EqualTo(2)); + Expect(s.rest().rest().count(), EqualTo(1)); + } + + [Test] + public void SeqWithMetaHasMeta() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + CPV v = new CPV(new object[] { 4, 5, 6 }); + IObj s = (IObj)v.seq(); + IObj obj = s.withMeta(meta); + + Expect(obj.meta(), SameAs(meta)); + mocks.VerifyAll(); + } + + [Test] + public void SeqReduceWithNoStartIterates() + { + MockRepository mocks = new MockRepository(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke(1, 2)).Return(5); + RMExpect.Call(fn.invoke(5, 3)).Return(7); + mocks.ReplayAll(); + + CPV v = new CPV(new object[] { 1, 2, 3 }); + IReduce r = (IReduce)v.seq(); + object ret = r.reduce(fn); + + Expect(ret, EqualTo(7)); + mocks.VerifyAll(); + } + + [Test] + public void SeqReduceWithStartIterates() + { + MockRepository mocks = new MockRepository(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke(20, 1)).Return(10); + RMExpect.Call(fn.invoke(10, 2)).Return(5); + RMExpect.Call(fn.invoke(5, 3)).Return(7); + mocks.ReplayAll(); + + CPV v = new CPV(new object[] { 1, 2, 3 }); + IReduce r = (IReduce)v.seq(); + object ret = r.reduce(fn, 20); + + Expect(ret, EqualTo(7)); + mocks.VerifyAll(); + } + + #endregion + + #region APersistentVector.RSeq tests + + // We'll do all the tests indirectly. + + [Test] + public void RSeqFirstAndRestWork() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + ISeq s = v.rseq(); + + Expect(s.first(), EqualTo(6)); + Expect(s.rest().first(), EqualTo(5)); + Expect(s.rest().rest().first(), EqualTo(4)); + Expect(s.rest().rest().rest(), Null); + } + + [Test] + public void RSeqIndexedWorks() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + ISeq s0 = v.rseq(); + IndexedSeq i0 = s0 as IndexedSeq; + + ISeq s1 = s0.rest(); + IndexedSeq i1 = s1 as IndexedSeq; + + Expect(i0.index(), EqualTo(0)); + Expect(i1.index(), EqualTo(1)); + } + + [Test] + public void RSeqCountWorks() + { + CPV v = new CPV(new object[] { 4, 5, 6 }); + ISeq s = v.rseq(); + + Expect(s.count(), EqualTo(3)); + Expect(s.rest().count(), EqualTo(2)); + Expect(s.rest().rest().count(), EqualTo(1)); + } + + [Test] + public void RSeqWithMetaHasMeta() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + CPV v = new CPV(new object[] { 4, 5, 6 }); + IObj s = (IObj)v.rseq(); + IObj obj = s.withMeta(meta); + + Expect(obj.meta(), SameAs(meta)); + mocks.VerifyAll(); + } + + [Test] + public void RSeqReduceWithNoStartIterates() + { + MockRepository mocks = new MockRepository(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke(3, 2)).Return(5); + RMExpect.Call(fn.invoke(5, 1)).Return(7); + mocks.ReplayAll(); + + CPV v = new CPV(new object[] { 1, 2, 3 }); + IReduce r = (IReduce)v.rseq(); + object ret = r.reduce(fn); + + Expect(ret, EqualTo(7)); + mocks.VerifyAll(); + } + + [Test] + public void RSeqReduceWithStartIterates() + { + MockRepository mocks = new MockRepository(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke(20, 3)).Return(10); + RMExpect.Call(fn.invoke(10, 2)).Return(5); + RMExpect.Call(fn.invoke(5, 1)).Return(7); + mocks.ReplayAll(); + + CPV v = new CPV(new object[] { 1, 2, 3 }); + IReduce r = (IReduce)v.rseq(); + object ret = r.reduce(fn, 20); + + Expect(ret, EqualTo(7)); + mocks.VerifyAll(); + } + + #endregion + + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/ARefTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ARefTests.cs new file mode 100644 index 00000000..c2cbe01e --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ARefTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add tests for Aref + class ARefTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/AReferenceTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/AReferenceTests.cs new file mode 100644 index 00000000..8f621ae2 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/AReferenceTests.cs @@ -0,0 +1,98 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + +namespace Clojure.Tests.LibTests +{ + + [TestFixture] + public class AReferenceTests : AssertionHelper + { + // AReference is abstract. We need a class to instantiate. + + class ConcreteAReference : AReference + { + public ConcreteAReference() : base() { } + public ConcreteAReference(IPersistentMap meta) : base(meta) { } + } + + + #region C-tor tests + + [Test] + public void Default_ctor_creates_with_null_metadata() + { + ConcreteAReference c = new ConcreteAReference(); + Expect(c.meta(), Null); + } + + [Test] + public void Map_ctor_creates_with_given_metadata() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + ConcreteAReference c = new ConcreteAReference(meta); + Expect(c.meta(), EqualTo(meta)); + + mocks.VerifyAll(); + } + + #endregion + + + #region IReference tests + + [Test] + public void AlterMeta_changes_meta() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.applyTo(null)).IgnoreArguments().Return(meta); + mocks.ReplayAll(); + + ConcreteAReference c = new ConcreteAReference(); + c.alterMeta(fn, null); + + Expect(c.meta(), EqualTo(meta)); + mocks.VerifyAll(); + } + + [Test] + public void ResetMeta_sets_meta() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + ConcreteAReference c = new ConcreteAReference(); + c.resetMeta(meta); + + Expect(c.meta(), EqualTo(meta)); + mocks.VerifyAll(); + } + + + #endregion + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/AgentTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/AgentTests.cs new file mode 100644 index 00000000..76bd2185 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/AgentTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add tests for Agent + class AgentTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/ArraySeqTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ArraySeqTests.cs new file mode 100644 index 00000000..cd033bb9 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ArraySeqTests.cs @@ -0,0 +1,214 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class ArraySeqTests : AssertionHelper + { + + #region C-tor tests + + [Test] + public void Create_on_nothing_returns_null() + { + ArraySeq a = ArraySeq.create(); + + Expect(a, Null); + } + + [Test] + public void Create_on_array_creates() + { + object[] array = new object[] { 1, 2, 3 }; + ArraySeq a = ArraySeq.create(array); + + Expect(a, Not.Null); + } + + [Test] + public void Create_on_null_returns_null() + { + ArraySeq a = ArraySeq.create(null); + + Expect(a, Null); + } + + [Test] + public void Create_on_array_has_no_meta() + { + object[] array = new object[] { 1, 2, 3 }; + ArraySeq a = ArraySeq.create(array); + + Expect(a.meta(), Null); + } + + [Test] + public void Create_on_array_and_index_creates() + { + object[] array = new object[] { 1, 2, 3 }; + ArraySeq a = ArraySeq.create(array,0); + + Expect(a, Not.Null); + } + + [Test] + public void Create_on_array_and_index_with_high_index_returns_null() + { + object[] array = new object[] { 1, 2, 3 }; + ArraySeq a = ArraySeq.create(array, 10); + + Expect(a, Null); + } + + [Test] + public void Create_on_array_and_index_has_no_meta() + { + object[] array = new object[] { 1, 2, 3 }; + ArraySeq a = ArraySeq.create(array,0); + + Expect(a.meta(), Null); + } + + #endregion + + #region IPersistentCollection tests + + [Test] + public void ArraySeq_has_correct_count_1() + { + object[] array = new object[] { 1, 2, 3 }; + ArraySeq a = ArraySeq.create(array); + + Expect(a.count(), EqualTo(3)); + } + + [Test] + public void ArraySeq_has_correct_count_2() + { + object[] array = new object[] { 1, 2, 3 }; + ArraySeq a = ArraySeq.create(array,1); + + Expect(a.count(), EqualTo(2)); + } + + #endregion + + + #region IReduce tests + + [Test] + public void ReduceWithNoStartIterates() + { + MockRepository mocks = new MockRepository(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke(2, 3)).Return(5); + RMExpect.Call(fn.invoke(5, 4)).Return(7); + mocks.ReplayAll(); + + object[] array = new object[] { 2, 3, 4 }; + ArraySeq a = ArraySeq.create(array); + object ret = a.reduce(fn); + + Expect(ret, EqualTo(7)); + + mocks.VerifyAll(); + } + + [Test] + public void ReduceWithStartIterates() + { + MockRepository mocks = new MockRepository(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke(20, 2)).Return(10); + RMExpect.Call(fn.invoke(10, 3)).Return(5); + RMExpect.Call(fn.invoke(5, 4)).Return(7); + mocks.ReplayAll(); + + object[] array = new object[] { 2, 3, 4 }; + ArraySeq a = ArraySeq.create(array); + object ret = a.reduce(fn, 20); + + Expect(ret, EqualTo(7)); + + mocks.VerifyAll(); + } + #endregion + + } + + [TestFixture] + public class ArraySeq_ISeq_Tests : ISeqTestHelper + { + object[] _array0; + object[] _array1; + ArraySeq _a0; + ArraySeq _a1; + + [SetUp] + public void Setup() + { + _array0 = new object[] { 1, 2, 3 }; + _array1 = new object[] { 2, 3 }; + _a0 = ArraySeq.create(_array0); + _a1 = ArraySeq.create(_array0, 1); + } + + [Test] + public void ArraySeq_ISeq_std_ctor_has_correct_elements() + { + VerifyISeqContents(_a0, _array0); + } + + [Test] + public void ArraySeq_ISeq_index_ctor_has_correct_elements() + { + VerifyISeqContents(_a1, _array1 ); + } + + [Test] + public void ArraySeq_ISeq_std_ctor_conses() + { + VerifyISeqCons(_a0, 4, _array0); + } + + [Test] + public void ArraySeq_ISeq_index_ctor_conses() + { + VerifyISeqCons(_a1, 4, _array1); + } + + + } + + [TestFixture] + public class ArraySeq_IObj_Tests : IObjTests + { + [SetUp] + public void Setup() + { + object[] array = new object[] { 1, 2, 3 }; + _objWithNullMeta = _obj = ArraySeq.create(array, 0); + _expectedType = typeof(ArraySeq); + } + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/ArrayStreamTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ArrayStreamTests.cs new file mode 100644 index 00000000..45377efb --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ArrayStreamTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add ArrayStream tests + class ArrayStreamTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/AtomTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/AtomTests.cs new file mode 100644 index 00000000..d4ea90b5 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/AtomTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add tests for Atom + class AtomTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/CachedSeqTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/CachedSeqTests.cs new file mode 100644 index 00000000..cd4b967d --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/CachedSeqTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: write tests for CachedSeq + class CachedSeqTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/ConsTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ConsTests.cs new file mode 100644 index 00000000..b01e1786 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ConsTests.cs @@ -0,0 +1,428 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; +using System.Collections; + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class ConsTests : AssertionHelper + { + #region C-tor tests + + [Test] + public void NoMetaCtorHasNoMeta() + { + Cons c = new Cons("abc",null); + Expect(c.meta(),Null); + } + + [Test] + public void MetaCtorHasMeta() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + Cons c = new Cons(meta, "abc", null); + + Expect(c.meta(), SameAs(meta)); + mocks.VerifyAll(); + } + + #endregion + + #region IPersistentCollection tests + + [Test] + public void CountOfOneItem() + { + Cons c = new Cons("abc", null); + + Expect(c.count(), EqualTo(1)); + } + + [Test] + public void CountOfTwoItems() + { + Cons c1 = new Cons("abc", null); + Cons c2 = new Cons("def", c1); + + Expect(c2.count(), EqualTo(2)); + } + + [Test] + public void SeqReturnsSelf() + { + Cons c1 = new Cons("abc", null); + + Expect(c1.seq(), SameAs(c1)); + } + + [Test] + public void EmptyIsNull() + { + // Test of ASeq + Cons c = new Cons("abc", null); + Expect(c.empty(), Null); + } + + [Test] + public void IPC_Cons_works() + { + Cons c1 = new Cons("abc", null); + IPersistentCollection ipc1 = c1 as IPersistentCollection; + + IPersistentCollection ipc2 = ipc1.cons("def"); + ISeq s = ipc2.seq(); + + Expect(s.first(), EqualTo("def")); + Expect(s.rest(), SameAs(c1)); + } + + #endregion + + #region ASeq tests + + // Some aspects of ASeq have been tested above. + // Here are the remaining bits + + private Cons CreateComplicatedCons() + { + Cons c1 = new Cons(1, null); + Cons c2 = new Cons(2, c1); + Cons c3 = new Cons("abc", null); + Cons c4 = new Cons(c3, c2); + Cons c5 = new Cons("def", c4); + + return c5; + } + + [Test] + public void EqualsDoesValueComparison() + { + Cons a = CreateComplicatedCons(); + Cons b = CreateComplicatedCons(); + + Expect(a.Equals(b)); + Expect(a, EqualTo(b)); + } + + [Test] + public void GetHashCodeComputesOnValue() + { + Cons a = CreateComplicatedCons(); + Cons b = CreateComplicatedCons(); + + Expect(a.GetHashCode(), EqualTo(b.GetHashCode())); + } + + + #endregion + + #region ASeq.ICollection tests + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ASeqICollCopyToFailsOnNullArray() + { + ICollection ic = new Cons(1, null); + ic.CopyTo(null, 0); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ASeqICollCopyToFailsOnInsufficientSpace() + { + ICollection ic = new Cons(1, new Cons(2, new Cons(3,null))); + Array arr = new object[2]; + ic.CopyTo(arr, 0); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ASeqICollCopyToFailsOnInsufficientSpace2() + { + ICollection ic = new Cons(1, new Cons(2, new Cons(3, null))); + Array arr = new object[10]; + ic.CopyTo(arr, 8); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ASeqICollCopyToFailsOnMultidimArray() + { + ICollection ic = new Cons(1, new Cons(2, new Cons(3, null))); + Array arr = Array.CreateInstance(typeof(int), 4, 4); + ic.CopyTo(arr, 0); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void ASeqICollCopyToFailsOnNegativeIndex() + { + ICollection ic = new Cons(1, new Cons(2, new Cons(3, null))); + Array arr = new object[10]; + ic.CopyTo(arr, -1); + } + + [Test] + public void ASeqICollCopyToCopiesToIndex0() + { + ICollection ic = new Cons(1, new Cons(2, new Cons(3, null))); + int[] arr = new int[4]; + ic.CopyTo(arr, 0); + + Expect(arr[0], EqualTo(1)); + Expect(arr[1], EqualTo(2)); + Expect(arr[2], EqualTo(3)); + Expect(arr[3], EqualTo(0)); + } + + [Test] + public void ASeqICollCopyToCopiesToIndexPositive() + { + ICollection ic = new Cons(1, new Cons(2, new Cons(3, null))); + int[] arr = new int[4]; + ic.CopyTo(arr, 1); + + Expect(arr[0], EqualTo(0)); + Expect(arr[1], EqualTo(1)); + Expect(arr[2], EqualTo(2)); + Expect(arr[3], EqualTo(3)); + } + + [Test] + public void ASeqICollCountWorks() + { + ICollection ic = new Cons(1, new Cons(2, new Cons(3, null))); + + Expect(ic.Count, EqualTo(3)); + } + + [Test] + public void ASeqICollIsSynchronized() + { + ICollection ic = new Cons(1, new Cons(2, new Cons(3, null))); + Expect(ic.IsSynchronized); + } + + [Test] + [ExpectedException(typeof(NotImplementedException))] + public void ASeqICollHasDoesntImplementSyncRoot() + { + ICollection ic = new Cons(1, new Cons(2, new Cons(3, null))); + Object o = ic.SyncRoot; + } + + [Test] + public void ASeqIEnumWorks() + { + ICollection ic = new Cons(1, new Cons(2, new Cons(3, null))); + IEnumerator e = ic.GetEnumerator(); + + Expect(e.MoveNext()); + Expect(e.Current, EqualTo(1)); + Expect(e.MoveNext()); + Expect(e.Current, EqualTo(2)); + Expect(e.MoveNext()); + Expect(e.Current, EqualTo(3)); + Expect(e.MoveNext(),False); + } + + + #endregion + + #region SeqIterator tests + + [Test] + public void SeqIteratorOnEmptySeqGoesNowhere() + { + SeqEnumerator s = new SeqEnumerator(null); + + Expect(s.MoveNext(), False); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void SeqIteratorOnEmptyHasNoCurrent() + { + SeqEnumerator s = new SeqEnumerator(null); + object o = s.Current; + } + + [Test] + public void SeqIteratorIterates() + { + Cons c = new Cons(1, new Cons(2, null)); + SeqEnumerator s = new SeqEnumerator(c); + + Expect(s.MoveNext()); + Expect(s.Current, EqualTo(1)); + Expect(s.MoveNext()); + Expect(s.Current, EqualTo(2)); + Expect(s.Current, EqualTo(2)); + Expect(s.MoveNext(), False); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void SeqIteratorMovedToEmptyHasNoCurrent() + { + Cons c = new Cons(1, new Cons(2, null)); + SeqEnumerator s = new SeqEnumerator(c); + + s.MoveNext(); + s.MoveNext(); + s.MoveNext(); + object o = s.Current; + } + + + [ExpectedException(typeof(InvalidOperationException))] + public void SeqIteratorResetAtBeginningWorks() + { + Cons c = new Cons(1, new Cons(2, null)); + SeqEnumerator s = new SeqEnumerator(c); + + s.Reset(); + + Expect(s.MoveNext()); + Expect(s.Current, EqualTo(1)); + Expect(s.MoveNext()); + Expect(s.Current, EqualTo(2)); + Expect(s.Current, EqualTo(2)); + Expect(s.MoveNext(), False); + } + + [Test] + public void SeqIteratorResetAtFirstWorks() + { + Cons c = new Cons(1, new Cons(2, null)); + SeqEnumerator s = new SeqEnumerator(c); + + s.MoveNext(); + s.Reset(); + + Expect(s.MoveNext()); + Expect(s.Current, EqualTo(1)); + Expect(s.MoveNext()); + Expect(s.Current, EqualTo(2)); + Expect(s.Current, EqualTo(2)); + Expect(s.MoveNext(), False); + } + + [Test] + public void SeqIteratorResetInMiddleWorks() + { + Cons c = new Cons(1, new Cons(2, null)); + SeqEnumerator s = new SeqEnumerator(c); + + s.MoveNext(); + s.MoveNext(); + s.Reset(); + + Expect(s.MoveNext()); + Expect(s.Current, EqualTo(1)); + Expect(s.MoveNext()); + Expect(s.Current, EqualTo(2)); + Expect(s.Current, EqualTo(2)); + Expect(s.MoveNext(), False); + } + + [Test] + public void SeqIteratorResetAtEndWorks() + { + Cons c = new Cons(1, new Cons(2, null)); + SeqEnumerator s = new SeqEnumerator(c); + + s.MoveNext(); + s.MoveNext(); + s.MoveNext(); + s.Reset(); + + Expect(s.MoveNext()); + Expect(s.Current, EqualTo(1)); + Expect(s.MoveNext()); + Expect(s.Current, EqualTo(2)); + Expect(s.Current, EqualTo(2)); + Expect(s.MoveNext(), False); + } + + #endregion + } + + [TestFixture] + public class Cons_ISeq_Tests : ISeqTestHelper + { + + [Test] + public void Cons_ISeq_has_correct_values() + { + Cons c1 = new Cons("def", null); + Cons c2 = new Cons("abc", c1); + + VerifyISeqContents(c2, new object[] { "abc", "def" }); + } + + [Test] + public void Cons_ISeq_with_meta_has_correct_values() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + Cons c1 = new Cons("def", null); + Cons c2 = new Cons(meta,"abc", c1); + + VerifyISeqContents(c2, new object[] { "abc", "def" }); + mocks.VerifyAll(); + } + + [Test] + public void Cons_ISeq_conses() + { + + Cons c1 = new Cons("def", null); + Cons c2 = new Cons("abc", c1); + + VerifyISeqCons(c2, "ghi", new object[] { "abc", "def" }); + } + + + + } + + + [TestFixture] + public class Cons_IMeta_Tests : IObjTests + { + [SetUp] + public void Setup() + { + IPersistentMap meta = PersistentHashMap.create("a", 1, "b", 2); + + Cons c1 = new Cons("abc", null); + Cons c2 = new Cons(meta,"def", c1); + _obj = c2; + _objWithNullMeta = c1; + _expectedType = typeof(Cons); + } + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/DelayTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/DelayTests.cs new file mode 100644 index 00000000..07d51a1c --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/DelayTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + class DelayTests + { + //TODO: Write Delay tests + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/FnSeqTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/FnSeqTests.cs new file mode 100644 index 00000000..93d64773 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/FnSeqTests.cs @@ -0,0 +1,120 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class FnSeqTests : AssertionHelper + { + #region C-tor tests + + // Couldn't think of anything except to make sure it doesn't throw an exception. + [Test] + public void CtorWorks() + { + FnSeq fs = new FnSeq("abc",null); + + Expect(fs, Not.Null); + } + + #endregion + } + + [TestFixture] + public class FnSeq_ISeq_Tests : ISeqTestHelper + { + object[] _restValues; + object[] _values; + MockRepository _mocks; + FnSeq _fs; + + [SetUp] + public void Setup() + { + _restValues = new object[] { 2, 3, 4 }; + _values = new object[] { "abc", 2, 3, 4 }; + _mocks = new MockRepository(); + IFn _fn = _mocks.StrictMock(); + RMExpect.Call(_fn.invoke()).Return(PersistentList.create(_restValues)); + + _fs = new FnSeq("abc", _fn); + + _mocks.ReplayAll(); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + + [Test] + public void FnSeq_ISeq_has_correct_values() + { + VerifyISeqContents(_fs, _values); + } + + [Test] + public void FnSeq_ISeq_conses() + { + VerifyISeqCons(_fs, 12, _values); + } + + [Test] + public void RestCachesResult() + { + _fs.rest(); + _fs.rest(); + } + + + + } + + [TestFixture] + public class FnSeq_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IFn fn = _mocks.StrictMock(); + RMExpect.Call(fn.invoke()).Return(null); + _mocks.ReplayAll(); + + FnSeq fs = new FnSeq("abc", fn); + + _obj = _objWithNullMeta = fs; + _expectedType = typeof(FnSeq); + } + + [TearDown] + public void TearDown() + { + _mocks.ReplayAll(); + } + + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/IObjTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/IObjTests.cs new file mode 100644 index 00000000..34f1ba72 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/IObjTests.cs @@ -0,0 +1,91 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; +using clojure.lang; + +namespace Clojure.Tests.LibTests +{ + /// + /// Base class for testing the IMeta interface functionality. + /// + public abstract class IObjTests : AssertionHelper + { + /// + /// Object to test for null meta. Set null if no test. Initialize in Setup. + /// + protected IObj _objWithNullMeta; + + + /// + /// The object to test. Initialize in Setup. + /// + protected IObj _obj; + + /// + /// Expected type of return from withMeta. Set null if no test. Initialize in Setup. + /// + protected Type _expectedType; + + + MockRepository _mocks = null; + IPersistentMap _meta = null; + + void InitMocks() + { + _mocks = new MockRepository(); + _meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + } + + + [Test] + public void withMeta_has_correct_meta() + { + InitMocks(); + IObj obj2 = _obj.withMeta(_meta); + Expect(obj2.meta(), SameAs(_meta)); + _mocks.VerifyAll(); + } + + [Test] + public void withMeta_returns_correct_type() + { + if (_expectedType == null) + return; + + InitMocks(); + IObj obj2 = _obj.withMeta(_meta); + Expect(obj2, TypeOf(_expectedType)); + _mocks.VerifyAll(); + } + + [Test] + public void withMeta_returns_self_if_no_change() + { + IObj obj2 = _obj.withMeta(_obj.meta()); + Expect(obj2, SameAs(_obj)); + } + + [Test] + public void Verify_Null_Meta() + { + if (_objWithNullMeta == null) + return; + Expect(_objWithNullMeta.meta(), Null); + } + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/ISeqTestHelper.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ISeqTestHelper.cs new file mode 100644 index 00000000..ba04a65e --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ISeqTestHelper.cs @@ -0,0 +1,54 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using clojure.lang; + +namespace Clojure.Tests.LibTests +{ + public class ISeqTestHelper : AssertionHelper + { + public void VerifyISeqContents(ISeq s, IList values) + { + int i=0; + + for (; s != null; s = s.rest(), i++) + Expect(s.first(), EqualTo(values[i])); + + Expect(i, EqualTo(values.Count)); + } + + public void VerifyISeqCons(ISeq s, object newVal, IList values) + { + ISeq newSeq = s.cons(newVal); + + Expect(newSeq.first(), EqualTo(newVal)); + VerifyISeqContents(newSeq.rest(), values); + } + + public void VerifyISeqRestTypes(ISeq s, Type type) + { + for ( ; s.rest() != null; s = s.rest()) + Expect(s.rest(), InstanceOfType(type)); + } + + public void VerifyISeqRestMaintainsMeta(ISeq s) + { + IPersistentMap meta = ((IMeta)s).meta(); + + for (; s.rest() != null; s = s.rest()) + Expect(((IMeta)s.rest()).meta(), EqualTo(meta)); + } + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/IteratorStreamTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/IteratorStreamTests.cs new file mode 100644 index 00000000..abc8291d --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/IteratorStreamTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + //TODO: add tests for IteratorStream + class IteratorStreamTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/KeywordTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/KeywordTests.cs new file mode 100644 index 00000000..6960f14c --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/KeywordTests.cs @@ -0,0 +1,239 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; +using System.Collections; + + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class KeywordTests : AssertionHelper + { + + #region c-tor tests + + [Test] + public void InternCreatesKeywordBasedOnSymbol() + { + Symbol sym = Symbol.intern("def","abc"); + Keyword k1 = Keyword.intern(sym); + Expect(k1.Name,EqualTo(sym.Name)); + Expect(k1.Namespace,EqualTo(sym.Namespace)); + } + + [Test] + public void InternReturnsSameKeywordOnEqualSym() + { + Symbol sym1 = Symbol.intern("def", "abc"); + Symbol sym2 = Symbol.intern("def", "abc"); + Keyword k1 = Keyword.intern(sym1); + Keyword k2 = Keyword.intern(sym2); + + Expect(Object.ReferenceEquals(k1, k2)); + } + + [Test] + public void Intern2CreatesKeywordBasedOnSymbol() + { + Keyword k1 = Keyword.intern("def","abc"); + Expect(k1.Name, EqualTo("abc")); + Expect(k1.Namespace, EqualTo("def")); + } + + [Test] + public void Intern2ReturnsSameKeywordOnEqualSym() + { + Keyword k1 = Keyword.intern("def", "abc"); + Keyword k2 = Keyword.intern("def", "abc"); + + Expect(Object.ReferenceEquals(k1, k2)); + } + + #endregion + + #region object override tests + + [Test] + public void ToStringReturnsStringNameWithColonPrepended() + { + Symbol sym1 = Symbol.intern("abc"); + Symbol sym2 = Symbol.intern("abc/def"); + Keyword k1 = Keyword.intern(sym1); + Keyword k2 = Keyword.intern(sym2); + + Expect(k1.ToString(), EqualTo(":abc")); + Expect(k2.ToString(), EqualTo(":abc/def")); + } + + [Test] + public void EqualOnIdentityIsTrue() + { + Symbol sym1 = Symbol.intern("abc"); + Keyword k1 = Keyword.intern(sym1); + + Expect(k1.Equals(k1)); + } + + [Test] + public void EqualsOnNonKeywordIsFalse() + { + Symbol sym1 = Symbol.intern("abc"); + Keyword k1 = Keyword.intern(sym1); + + Expect(k1.Equals(sym1), False); + } + + //[Test] + //public void EqualsDependsOnSym() + //{ + // Symbol sym1 = Symbol.intern("abc"); + // Symbol sym2 = Symbol.intern("abc"); + // Keyword k1 = Keyword.intern(sym1); + // Keyword k2 = Keyword.intern(sym2); + // // I don't know how we ever create two keywords that will force + // // the code to go into the sym.equals part of the code. + // // At least, not through the factory methods. + //} + + [Test] + public void HashCodeDependsOnValue() + { + Symbol sym1 = Symbol.intern("abc"); + Symbol sym2 = Symbol.intern("abc/def"); + Keyword k1 = Keyword.intern(sym1); + Keyword k2 = Keyword.intern(sym2); + + Expect(k1.GetHashCode(), Not.EqualTo(k2.GetHashCode())); + } + + + #endregion + + #region Named tests + + public void NameAndNamespaceComeFromTheSymbol() + { + Symbol sym1 = Symbol.intern("def", "abc"); + Keyword k1 = Keyword.intern(sym1); + Symbol sym2 = Symbol.intern("abc"); + Keyword k2 = Keyword.intern(sym2); + Expect(k1.Name, EqualTo("abc")); + Expect(k1.Namespace, EqualTo("def")); + Expect(k2.Name, EqualTo("abc")); + Expect(k2.Namespace, Null); + } + + #endregion + + #region IFn Tests + + [Test] + public void Invoke2IndexesIntoItsFirstArg() + { + Keyword k1 = Keyword.intern(Symbol.intern("abc")); + Keyword k2 = Keyword.intern(Symbol.intern("ab")); + + IDictionary dict = new Hashtable(); + dict[k1] = 7; + dict["abc"] = 8; + + Expect(k1.invoke(dict), EqualTo(7)); + Expect(k2.invoke(dict), Null); + } + + [Test] + public void Invoke3IndexesIntoItsFirstArg() + { + Keyword k1 = Keyword.intern(Symbol.intern("abc")); + Keyword k2 = Keyword.intern(Symbol.intern("ab")); + + IDictionary dict = new Hashtable(); + dict[k1] = 7; + dict["abc"] = 8; + + Expect(k1.invoke(dict, 20), EqualTo(7)); + Expect(k2.invoke(dict, 20), EqualTo(20)); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void InvokeOnNoArgsFails() + { + Keyword k1 = Keyword.intern(Symbol.intern("abc")); + object o = k1.invoke(); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void InvokeOnTooManyArgsFails() + { + Keyword k1 = Keyword.intern(Symbol.intern("abc")); + IDictionary dict = new Hashtable(); + dict[k1] = 7; + dict["abc"] = 8; + + object o = k1.invoke(dict, 20, null); + } + + #endregion + + #region IComparable tests + + [Test] + [ExpectedException(typeof(InvalidCastException))] + public void CompareToNonKeywordFails() + { + Symbol s1 = Symbol.intern("abc"); + Keyword k1 = Keyword.intern(s1); + int c = k1.CompareTo(s1); + } + + [Test] + public void CompareToEqualKeywordIsZero() + { + Keyword k1 = Keyword.intern(Symbol.intern("abc")); + Keyword k2 = Keyword.intern(Symbol.intern("abc")); + + Expect(k1.CompareTo(k2), EqualTo(0)); + } + + [Test] + public void CompareDependsOnSymbolCompare() + { + Symbol sym1 = Symbol.intern("abc"); + Symbol sym2 = Symbol.intern("a", "abc"); + Symbol sym3 = Symbol.intern("b", "abc"); + Keyword k1 = Keyword.intern(sym1); + Keyword k2 = Keyword.intern(sym2); + Keyword k3 = Keyword.intern(sym3); + + Expect(k1.CompareTo(k2), LessThan(0)); + Expect(k2.CompareTo(k1), GreaterThan(0)); + Expect(k1.CompareTo(k3), LessThan(0)); + Expect(k3.CompareTo(k1), GreaterThan(0)); + } + + + #endregion + } + +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/LazilyPersistentVectorTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/LazilyPersistentVectorTests.cs new file mode 100644 index 00000000..e5549288 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/LazilyPersistentVectorTests.cs @@ -0,0 +1,220 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class LazilyPersistentVectorTests : AssertionHelper + { + #region C-tor tests + + [Test] + public void CreateOwningOnNoParamsReturnsEmptyVector() + { + IPersistentVector v = LazilyPersistentVector.createOwning(); + Expect(v.count(),EqualTo(0)); + } + + [Test] + public void CreatingOwningOnParamsReturnsVector() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + Expect(v.count(), EqualTo(3)); + Expect(v.nth(0), EqualTo(1)); + Expect(v.nth(1), EqualTo(2)); + Expect(v.nth(2), EqualTo(3)); + } + + [Test] + public void CreateOnEmptySeqReturnsEmptyVector() + { + IPersistentVector v = LazilyPersistentVector.create(new object[] {}); + Expect(v.count(), EqualTo(0)); + } + + [Test] + public void CreateOnNonEmptyCollectionReturnsVector() + { + IPersistentVector v = LazilyPersistentVector.createOwning(new object[] {1, 2, 3}); + Expect(v.count(), EqualTo(3)); + Expect(v.nth(0), EqualTo(1)); + Expect(v.nth(1), EqualTo(2)); + Expect(v.nth(2), EqualTo(3)); + } + + + #endregion + + #region IPersistentVector tests + + [Test] + public void NthInRangeWorks() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + + Expect(v.count(), EqualTo(3)); + Expect(v.nth(0), EqualTo(1)); + Expect(v.nth(1), EqualTo(2)); + Expect(v.nth(2), EqualTo(3)); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void NthOutOfRangeLowFails() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + + Expect(v.nth(-4), EqualTo(1)); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void NthOutOfRangeHighFails() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + + Expect(v.nth(4), EqualTo(1)); + } + + [Test] + public void AssocnInRangeModifies() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + IPersistentVector v2 = v.assocN(1, 4); + + Expect(v.count(), EqualTo(3)); + Expect(v.nth(0), EqualTo(1)); + Expect(v.nth(1), EqualTo(2)); + Expect(v.nth(2), EqualTo(3)); + + Expect(v2.count(), EqualTo(3)); + Expect(v2.nth(0), EqualTo(1)); + Expect(v2.nth(1), EqualTo(4)); + Expect(v2.nth(2), EqualTo(3)); + } + + [Test] + public void AssocnAtEndModifies() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + IPersistentVector v2 = v.assocN(3, 4); + + Expect(v.count(), EqualTo(3)); + Expect(v.nth(0), EqualTo(1)); + Expect(v.nth(1), EqualTo(2)); + Expect(v.nth(2), EqualTo(3)); + + Expect(v2.count(), EqualTo(4)); + Expect(v2.nth(0), EqualTo(1)); + Expect(v2.nth(1), EqualTo(2)); + Expect(v2.nth(2), EqualTo(3)); + Expect(v2.nth(3), EqualTo(4)); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void AssocNOutOfRangeLowFails() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + IPersistentVector v2 = v.assocN(-4, 4); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void AssocNOutOfRangeHighFails() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + IPersistentVector v2 = v.assocN(4, 4); + } + + + [Test] + public void ConsAddsAtEnd() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + IPersistentVector v2 = v.cons(4); + + Expect(v.count(), EqualTo(3)); + Expect(v.nth(0), EqualTo(1)); + Expect(v.nth(1), EqualTo(2)); + Expect(v.nth(2), EqualTo(3)); + + Expect(v2.count(), EqualTo(4)); + Expect(v2.nth(0), EqualTo(1)); + Expect(v2.nth(1), EqualTo(2)); + Expect(v2.nth(2), EqualTo(3)); + Expect(v2.nth(3), EqualTo(4)); + } + + [Test] + public void LengthWorks() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + + Expect(v.length(), EqualTo(3)); + } + + #endregion + + #region IPersistentStack tests + + [Test] + public void PopOnNonEmptyWorks() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + IPersistentVector v2 = (IPersistentVector)((IPersistentStack)v).pop(); + + Expect(v.count(), EqualTo(3)); + Expect(v.nth(0), EqualTo(1)); + Expect(v.nth(1), EqualTo(2)); + Expect(v.nth(2), EqualTo(3)); + + Expect(v2.count(), EqualTo(2)); + Expect(v2.nth(0), EqualTo(1)); + Expect(v2.nth(1), EqualTo(2)); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void PopOnEmptyFails() + { + IPersistentVector v = LazilyPersistentVector.createOwning(); + IPersistentStack v2 = ((IPersistentStack)v).pop(); + } + + #endregion + } + + [TestFixture] + public class LazilyPersistentVector_IObj_Tests : IObjTests + { + [SetUp] + public void Setup() + { + IPersistentVector v = LazilyPersistentVector.createOwning(1, 2, 3); + + _obj = _objWithNullMeta = (IObj)v; + _expectedType = typeof(LazilyPersistentVector); + } + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/LazyConsTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/LazyConsTests.cs new file mode 100644 index 00000000..0a230c0e --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/LazyConsTests.cs @@ -0,0 +1,123 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class LazyConsTests : AssertionHelper + { + + #region C-tor tests + + // Couldn't think of anything except to make sure it doesn't throw an exception. + [Test] + public void CtorWorks() + { + LazyCons lc = new LazyCons(null); + + Expect(lc, Not.Null); + } + + #endregion + } + + [TestFixture] + public class LazyCons_ISeq_Tests : ISeqTestHelper + { + MockRepository _mocks ; + IFn _fn; + LazyCons _lc; + object[] _values; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + _fn = _mocks.StrictMock(); + RMExpect.Call(_fn.invoke()).Return(10); + RMExpect.Call(_fn.invoke(null)).Return(new Cons(20,null)); + _lc = new LazyCons(_fn); + _values = new object[] { 10, 20 }; + _mocks.ReplayAll(); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + [Test] + public void ISeq_has_proper_values() + { + VerifyISeqContents(_lc, _values); + } + + [Test] + public void First_caches() + { + _lc.first(); + _lc.first(); + + // Need to meet expectation that _rest is called. + _lc.rest(); + } + + [Test] + public void Rest_calcs_first() + { + _lc.rest(); + } + + [Test] + public void Rest_caches() + { + _lc.rest(); + _lc.rest(); + } + + + + } + + [TestFixture] + public class LazyCons_IObj_Tests : IObjTests + { + [SetUp] + public void Setup() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke()).Return(10); + RMExpect.Call(fn.invoke(null)).Return(null); + mocks.ReplayAll(); + + _objWithNullMeta = new LazyCons(fn); + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(LazyCons); + + mocks.VerifyAll(); + } + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/LispReaderTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/LispReaderTests.cs new file mode 100644 index 00000000..99d45e36 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/LispReaderTests.cs @@ -0,0 +1,1789 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; +using java.math; + +using clojure.lang.Readers; + + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class LispReaderTests : AssertionHelper + { + #region matchNumber tests + + [Test] + public void MatchNumberMatchesZero() + { + object o1 = LispReader.matchNumber("0"); + object o2 = LispReader.matchNumber("-0"); + object o3 = LispReader.matchNumber("+0"); + + Expect(o1, EqualTo(0)); + Expect(o2, EqualTo(0)); + Expect(o3, EqualTo(0)); + } + + [Test] + public void MatchNumberMatchesDecimal() + { + object o1 = LispReader.matchNumber("123"); + object o2 = LispReader.matchNumber("+123"); + object o3 = LispReader.matchNumber("-123"); + object o4 = LispReader.matchNumber("123456789123456789123456789"); + + Expect(o1, EqualTo(123)); + Expect(o2, EqualTo(123)); + Expect(o3, EqualTo(-123)); + Expect(o4, EqualTo(new BigInteger("123456789123456789123456789"))); + } + + [Test] + public void MatchNumberMatchesHexadecimal() + { + object o1 = LispReader.matchNumber("0X12A"); + object o2 = LispReader.matchNumber("0xFFF"); + object o3 = LispReader.matchNumber("0xFFFFFFFFFFFFFFFFFFFFFFFF"); + + Expect(o1, EqualTo(0x12A)); + Expect(o2, EqualTo(0xFFF)); + Expect(o3, EqualTo(new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFF", 16))); + } + + + [Test] + public void MatchNumberMatchesOctal() + { + object o1 = LispReader.matchNumber("0123"); + object o2 = LispReader.matchNumber("+0123"); + object o3 = LispReader.matchNumber("-0123"); + object o4 = LispReader.matchNumber("01234567012345670123456777"); + + Expect(o1, EqualTo(83)); + Expect(o2, EqualTo(83)); + Expect(o3, EqualTo(-83)); + Expect(o4, EqualTo(new BigInteger("1234567012345670123456777", 8))); + } + + [Test] + public void MatchNumberMatchesSpecifiedRadix() + { + object o1 = LispReader.matchNumber("2R1100"); + object o2 = LispReader.matchNumber("4R123"); + object o3 = LispReader.matchNumber("-4R123"); + object o4 = LispReader.matchNumber("30R1234AQ"); + + Expect(o1, EqualTo(12)); + Expect(o2, EqualTo(27)); + Expect(o3, EqualTo(-27)); + Expect(o4, EqualTo(new BigInteger("1234AQ", 30).longValue())); + } + + [Test] + public void MatchNumberMatchesFloats() + { + object o1 = LispReader.matchNumber("123.7"); + object o2 = LispReader.matchNumber("-123.7E4"); + object o3 = LispReader.matchNumber("+1.237e4"); + object o4 = LispReader.matchNumber("+1.237e-4"); + object o5 = LispReader.matchNumber("1.237e+4"); + + Expect(o1, EqualTo(123.7)); + Expect(o2, EqualTo(-1237000.0)); + Expect(o3, EqualTo(1.237e4)); + Expect(o4, EqualTo(1.237e-4)); + Expect(o5, EqualTo(1.237e4)); + } + + [Test] + public void MatchNumberMatchesDecimals() + { + object o1 = LispReader.matchNumber("123.7M"); + // MS implementation of BigDecimal parser does not allow these. + //object o2 = LispReader.matchNumber("-123.7E4M"); + //object o3 = LispReader.matchNumber("+1.237e4M"); + //object o4 = LispReader.matchNumber("+1.237e-4M"); + //object o5 = LispReader.matchNumber("1.237e+4M"); + + Expect(o1, EqualTo(new BigDecimal("123.7"))); + //Expect(o2, EqualTo(-1237000.0M)); + //Expect(o3, EqualTo(1.237e4M)); + //Expect(o4, EqualTo(1.237e-4M)); + //Expect(o5, EqualTo(1.237e4M)); + } + + [Test] + public void MatchNumberMatchesRatios() + { + object o1 = LispReader.matchNumber("12/1"); + object o2 = LispReader.matchNumber("12/4"); + object o3 = LispReader.matchNumber("12/5"); + object o4 = LispReader.matchNumber("12345678900000/123456789"); + + Expect(o1, EqualTo(12)); + Expect(o2, EqualTo(3)); + Expect(o3, EqualTo(new Ratio(new BigInteger("12"),new BigInteger("5")))); + Expect(o4, EqualTo(100000)); + } + + [Test] + public void MatchNumberReadsWholeString() + { + object o1 = LispReader.matchNumber(" 123"); + object o2 = LispReader.matchNumber("123 "); + object o3 = LispReader.matchNumber(" 12.3"); + object o4 = LispReader.matchNumber("12.3 "); + object o5 = LispReader.matchNumber(" 1/23"); + object o6 = LispReader.matchNumber("1/23 "); + + Expect(o1, Null); + Expect(o2, Null); + Expect(o3, Null); + Expect(o4, Null); + Expect(o5, Null); + Expect(o6, Null); + } + + [Test] + public void MatchNumberFailsToMatchWeirdThings() + { + object o1 = LispReader.matchNumber("123a"); + object o2 = LispReader.matchNumber("0x123Z"); + object o4 = LispReader.matchNumber("12.4/24.2"); + object o5 = LispReader.matchNumber("1.7M3"); + + Expect(o1, Null); + Expect(o2, Null); + Expect(o4, Null); + Expect(o5, Null); + } + + + [Test] + [ExpectedException(typeof(java.lang.NumberFormatException))] + public void MatchNumberFailsOnRadixSnafu() + { + object o3 = LispReader.matchNumber("10RAA"); + } + #endregion + + #region Helpers + + static TextReader CreatePushbackReaderFromString(string s) + { + return new StringReader(s); + } + + static object ReadFromString(string s) + { + return LispReader.read(CreatePushbackReaderFromString(s),true,null,false); + } + + static LineNumberingReader CreateLNPBRFromString(string s) + { + return new LineNumberingReader(new StringReader(s)); + } + + static object ReadFromStringNumbering(string s) + { + return LispReader.read(CreateLNPBRFromString(s),true,null,false); + } + + + #endregion + + #region Testing EOF + + [Test] + public void EofValueReturnedOnEof() + { + object o = LispReader.read(CreatePushbackReaderFromString(" "), false, 7, false); + Expect(o, EqualTo(7)); + } + + [Test] + [ExpectedException(typeof(System.IO.EndOfStreamException))] + public void EofValueFailsOnEof() + { + object o = LispReader.read(CreatePushbackReaderFromString(" "), true, 7, false); + } + + #endregion + + #region Testing a few numbers + + [Test] + public void ReadReadsIntegers() + { + object o1 = ReadFromString("123"); + object o2 = ReadFromString("-123"); + object o3 = ReadFromString("+123"); + object o4 = ReadFromString("123456789123456789123456789"); + + Expect(o1, EqualTo(123)); + Expect(o2, EqualTo(-123)); + Expect(o3, EqualTo(123)); + Expect(o4, EqualTo(new BigInteger("123456789123456789123456789"))); + } + + [Test] + public void ReadReadsFloats() + { + object o1 = ReadFromString("123.4"); + object o2 = ReadFromString("-123.4E4"); + object o3 = ReadFromString("+123.4E-2"); + + Expect(o1, EqualTo(123.4)); + Expect(o2, EqualTo(-123.4E4)); + Expect(o3, EqualTo(123.4E-2)); + } + + [Test] + public void ReadReadsRatios() + { + object o1 = ReadFromString("123/456"); + object o2 = ReadFromString("-123/456"); + object o3 = ReadFromString("+123/456"); + + Expect(o1, TypeOf(typeof(Ratio))); + Expect(o2, TypeOf(typeof(Ratio))); + Expect(o3, TypeOf(typeof(Ratio))); + } + + + + #endregion + + #region Special tokens + + [Test] + public void SlashAloneIsSlash() + { + object o = ReadFromString("/"); + Expect(o, TypeOf(typeof(Symbol))); + Expect(((Symbol)o).Name, EqualTo("/")); + Expect(((Symbol)o).Namespace, Null); + } + + [Test] + public void ClojureSlashIsSpecial() + { + object o = ReadFromString("clojure.core//"); + Expect(o, TypeOf(typeof(Symbol))); + Expect(((Symbol)o).Name, EqualTo("/")); + Expect(((Symbol)o).Namespace, EqualTo("clojure.core")); + } + + [Test] + public void TrueReturnsT() + { + object o = ReadFromString("true"); + Expect(o, TypeOf(typeof(bool))); + Expect(o,EqualTo(true)); + } + + [Test] + public void FalseReturnsF() + { + object o = ReadFromString("false"); + Expect(o, TypeOf(typeof(bool))); + Expect(o, EqualTo(false)); + } + + [Test] + public void NilIsNull() + { + object o = ReadFromString("nil"); + Expect(o, Null); + } + + #endregion + + #region Symbolic tests + + [Test] + public void ReadReadsSymbolWithNoNS() + { + object o1 = ReadFromString("abc"); + + Expect(o1, TypeOf(typeof(Symbol))); + Expect(((Symbol)o1).Name, EqualTo("abc")); + Expect(((Symbol)o1).Namespace, Null); + } + + [Test] + public void ReadReadsSymbolWithNS() + { + object o1 = ReadFromString("ab/cd"); + + Expect(o1, TypeOf(typeof(Symbol))); + Expect(((Symbol)o1).Name, EqualTo("cd")); + Expect(((Symbol)o1).Namespace, EqualTo("ab")); + } + + [Test] + public void TwoSlashesIsOkayApparently() + { + object o1 = ReadFromString("ab/cd/e"); + + Expect(o1, TypeOf(typeof(Symbol))); + Expect(((Symbol)o1).Name, EqualTo("e")); + Expect(((Symbol)o1).Namespace, EqualTo("ab/cd")); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void NamespaceEndingWithColonSlashIsBad() + { + object o1 = ReadFromString("ab:/cd"); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void NameEndingWithColonIsBad() + { + object o1 = ReadFromString("ab/cd:"); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void NameEndingWithColonIsBad2() + { + object o1 = ReadFromString("cd:"); + } + + [Test] + public void NameMayContainMultipleColons() + { + object o1 = ReadFromString("a:b:c/d:e:f"); + Expect(o1, TypeOf(typeof(Symbol))); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void NameContainingDoubleColonNotAtBeginningIsBad() + { + object o1 = ReadFromString("ab::cd"); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void NamespaceContainingDoubleColonNotAtBeginningIsBad() + { + object o1 = ReadFromString("ab::cd/ef"); + } + + #endregion + + #region Keyword tests + + [Test] + public void LeadingColonIsKeyword() + { + object o1 = ReadFromString(":abc"); + Expect(o1, TypeOf(typeof(Keyword))); + Expect(((Keyword)o1).Namespace, Null); + Expect(((Keyword)o1).Name, EqualTo("abc")); + } + + [Test] + public void LeadingColonWithNSIsKeyword() + { + object o1 = ReadFromString(":ab/cd"); + Expect(o1, TypeOf(typeof(Keyword))); + Expect(((Keyword)o1).Namespace, EqualTo("ab")); + Expect(((Keyword)o1).Name, EqualTo("cd")); + } + + // TODO: Add more tests dealing with :: resolution. + + [Test] + public void LeadingDoubleColonMakesKeywordInCurrentNamespace() + { + object o1 = ReadFromString("::abc"); + Expect(o1, TypeOf(typeof(Keyword))); + Expect(((Keyword)o1).Namespace, EqualTo(((Namespace)RT.CURRENT_NS.deref()).Name.Name)); + Expect(((Keyword)o1).Name, EqualTo("abc")); + } + + // At one time, this test worked. Now, according to the documentation, it should not work. Did something change? Never mind. + //[Test] + //public void LeadingDoubleColonDoesNotSetNamespaceIfPeriodsInName() + //{ + // object o1 = ReadFromString("::ab.cd"); + // Expect(o1, TypeOf(typeof(Keyword))); + // Expect(((Keyword)o1).Namespace, Null); + // Expect(((Keyword)o1).Name, EqualTo("ab.cd")); + //} + + #endregion + + #region String tests + + [Test] + public void DoubleQuotesSurroundAString() + { + object o1 = ReadFromString("\"abc\""); + Expect(o1,TypeOf(typeof(string))); + Expect(o1, EqualTo("abc")); + } + + [Test] + [ExpectedException(typeof(System.IO.EndOfStreamException))] + public void NoEndingDoubleQuoteFails() + { + object o1 = ReadFromString("\"abc"); + } + + [Test] + public void EmptyStringWorks() + { + object o1 = ReadFromString("\"\""); + Expect(o1, TypeOf(typeof(string))); + Expect(o1, EqualTo(String.Empty)); + + } + + [Test] + public void EscapesWorkInStrings() + { + char[] chars = new char[] { + '"', 'a', + '\\', 't', 'b', + '\\', 'r', 'c', + '\\', 'n', 'd', + '\\', '\\', 'e', + '\\', '"', 'f', + '\\', 'b', 'g', + '\\', 'f', 'h', '"' + }; + + string s = new String(chars); + Expect(s.Length, EqualTo(24)); + + + object o1 = ReadFromString(s); + Expect(o1, EqualTo("a\tb\rc\nd\\e\"f\bg\fh")); + } + + [Test] + [ExpectedException(typeof(System.IO.EndOfStreamException))] + public void EOFinEscapeIsError() + { + char[] chars = new char[] { + '"', 'a', + '\\', 't', 'b', + '\\', 'r', 'c', + '\\', 'n', 'd', + '\\' + }; + string s = new String(chars); + + object o1 = ReadFromString(s); + } + + [Test] + public void UnicodeEscapeInsertsUnicodeCharacter() + { + char[] chars = new char[] { + '"', 'a', + '\\', 'u', '1', '2', 'C', '4', + 'b', '"' + }; + + string s = new String(chars); + + object o1 = ReadFromString(s); + Expect(o1, EqualTo("a\u12C4b")); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void UnicodeEscapeWithBadCharacterFails() + { + char[] chars = new char[] { + '"', 'a', + '\\', 'u', '1', '2', 'X', '4', + 'b', '"' + }; + string s = new String(chars); + + object o1 = ReadFromString(s); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void UnicodeEscapeWithEOFFails() + { + char[] chars = new char[] { + '"', 'a', + '\\', 'u', '1', '2', 'A', '"' + }; + string s = new String(chars); + + object o1 = ReadFromString(s); + } + + + [Test] + public void OctalEscapeInsertsCharacter() + { + char[] chars = new char[] { + '"', 'a', + '\\', '1', '2', '4', + 'b', '"' + }; + string s = new String(chars); + + object o1 = ReadFromString(s); + Expect(o1, EqualTo("a\x0054b")); // hex/octal conversion + } + + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void OctalEscapeWithBadDigitFails() + { + char[] chars = new char[] { + '"', 'a', + '\\', '1', '8', '4', + 'b', '"' + }; + string s = new String(chars); + + object o1 = ReadFromString(s); + } + + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void OctalEscapeWithEOFFails() + { + char[] chars = new char[] { + '"', 'a', + '\\', '1', '8', '"' + }; + string s = new String(chars); + + object o1 = ReadFromString(s); + } + + [ExpectedException(typeof(ArgumentException))] + public void OctalEscapeOutOfRangeFails() + { + char[] chars = new char[] { + '"', 'a', + '\\', '4', '7', '7', + 'b', '"' + }; + string s = new String(chars); + + object o1 = ReadFromString(s); + } + + + #endregion + + #region Character tests + + [Test] + public void BackslashYieldsNextCharacter() + { + object o1 = ReadFromString("\\a"); + Expect(o1, TypeOf(typeof(Char))); + Expect(o1, EqualTo('a')); + } + + [Test] + public void BackslashYieldsNextCharacterStoppingAtTerminator() + { + object o1 = ReadFromString("\\a b"); + Expect(o1, TypeOf(typeof(Char))); + Expect(o1, EqualTo('a')); + } + + [Test] + [ExpectedException(typeof(System.IO.EndOfStreamException))] + public void BackslashFollowedByEOFFails() + { + object o1 = ReadFromString("\\"); + } + + [Test] + public void BackslashRecognizesSpecialNames() + { + object o1 = ReadFromString("\\newline"); + object o2 = ReadFromString("\\space"); + object o3 = ReadFromString("\\tab"); + object o4 = ReadFromString("\\backspace"); + object o5 = ReadFromString("\\formfeed"); + object o6 = ReadFromString("\\return"); + + Expect(o1, EqualTo('\n')); + Expect(o2, EqualTo(' ')); + Expect(o3, EqualTo('\t')); + Expect(o4, EqualTo('\b')); + Expect(o5, EqualTo('\f')); + Expect(o6, EqualTo('\r')); + } + + [Test] + public void BackslashRecognizesUnicode() + { + object o1 = ReadFromString("\\u12C4"); + Expect(o1, EqualTo('\u12C4')); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void BackslashUnicodeWithEOFFails() + { + object o1 = ReadFromString("\\u12C 4"); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void BackslashUnicodeInBadRangeFails() + { + object o1 = ReadFromString("\\uDAAA"); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void BackslashUnicodeWithBadDigitFails() + { + object o1 = ReadFromString("\\u12X4"); + } + + [Test] + public void BackslashRecognizesOctal() + { + object o1 = ReadFromString("\\o124"); + Expect(o1, EqualTo('\x54')); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void BackslashOctalWithEOFFails() + { + object o1 = ReadFromString("\\u12 4"); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void BackslashOctalInBadRangeFails() + { + object o1 = ReadFromString("\\o444"); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void BackslashOctalWithBadDigitFails() + { + object o1 = ReadFromString("\\o128"); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void BackslashOctalWithTooManyDigitsFails() + { + object o1 = ReadFromString("\\o0012 aa"); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void BackslashWithOtherFails() + { + object o1 = ReadFromString("\\aa"); + } + + #endregion + + #region comment tests + + [Test] + public void SemicolonIgnoresToEndOfLine() + { + object o1 = ReadFromString(" ; ignore \n 123"); + Expect(o1, EqualTo(123)); + } + + [Test] + public void SharpBangIgnoresToEndOfLine() + { + object o1 = ReadFromString(" #! ignore \n 123"); + Expect(o1, EqualTo(123)); + } + + #endregion + + #region Discard tests + + [Test] + public void SharpUnderscoreIgnoresNextForm() + { + object o1 = ReadFromString("#_ (1 2 3) 4"); + Expect(o1, EqualTo(4)); + } + + [Test] + public void SharpUnderscoreIgnoresNextFormInList() + { + object o1 = ReadFromString("( abc #_ (1 2 3) 12)"); + Expect(o1, TypeOf(typeof(PersistentList))); + PersistentList pl = o1 as PersistentList; + Expect(pl.count(), EqualTo(2)); + Expect(pl.first(), TypeOf(typeof(Symbol))); + Expect(((Symbol)pl.first()).Name, EqualTo("abc")); + Expect(((Symbol)pl.first()).Namespace, Null); + Expect(pl.rest().first(), TypeOf(typeof(int))); + Expect(pl.rest().first(), EqualTo(12)); + Expect(pl.rest().rest(), Null); + } + + #endregion + + #region List tests + + [Test] + public void CanReadBasicList() + { + Object o1 = ReadFromString("(abc 12)"); + Expect(o1, TypeOf(typeof(PersistentList))); + PersistentList pl = o1 as PersistentList; + Expect(pl.count(), EqualTo(2)); + Expect(pl.first(), TypeOf(typeof(Symbol))); + Expect(((Symbol)pl.first()).Name, EqualTo("abc")); + Expect(((Symbol)pl.first()).Namespace, Null); + Expect(pl.rest().first(), TypeOf(typeof(int))); + Expect(pl.rest().first(), EqualTo(12)); + Expect(pl.rest().rest(), Null); + } + + [Test] + public void CanReadEmptyList() + { + Object o1 = ReadFromString("( )"); + Expect(o1, InstanceOfType(typeof(IPersistentList))); + IPersistentList pl = o1 as IPersistentList; + Expect(pl.count(), EqualTo(0)); + } + + [Test] + public void CanReadNestedList() + { + Object o1 = ReadFromString("(a (b c) d)"); + Expect(o1, InstanceOfType(typeof(IPersistentList))); + IPersistentList pl = o1 as IPersistentList; + ISeq seq = pl.seq(); + Expect(pl.count(), EqualTo(3)); + Expect(seq.rest().first(), InstanceOfType(typeof(IPersistentList))); + IPersistentList sub = seq.rest().first() as IPersistentList; + Expect(sub.count(), EqualTo(2)); + } + + [Test] + [ExpectedException(typeof(System.IO.EndOfStreamException))] + public void MissingListTerminatorFails() + { + Object o1 = ReadFromString("(a b 1 2"); + } + + [Test] + public void ListGetsLineNumber() + { + Object o1 = ReadFromStringNumbering("\n\n(a b \n1 2)"); + Expect(o1, InstanceOfType(typeof(IObj))); + IObj io = o1 as IObj; + Expect(io.meta().valAt(Keyword.intern(null,"line")), EqualTo(3)); + } + + #endregion + + #region VectorTests + + [Test] + public void CanReadBasicVector() + { + Object o1 = ReadFromString("[abc 12]"); + Expect(o1, TypeOf(typeof(LazilyPersistentVector))); + LazilyPersistentVector pl = o1 as LazilyPersistentVector; + Expect(pl.count(), EqualTo(2)); + Expect(pl.nth(0), TypeOf(typeof(Symbol))); + Expect(((Symbol)pl.nth(0)).Name, EqualTo("abc")); + Expect(((Symbol)pl.nth(0)).Namespace, Null); + Expect(pl.nth(1), TypeOf(typeof(int))); + Expect(pl.nth(1), EqualTo(12)); + } + + [Test] + public void CanReadEmptyVector() + { + Object o1 = ReadFromString("[ ]"); + Expect(o1, InstanceOfType(typeof(IPersistentVector))); + IPersistentVector v = o1 as IPersistentVector; + Expect(v.count(), EqualTo(0)); + } + + [Test] + public void VectorCanContainNestedList() + { + Object o1 = ReadFromString("[a (b c) d]"); + Expect(o1, InstanceOfType(typeof(IPersistentVector))); + IPersistentVector v = o1 as IPersistentVector; + Expect(v.count(), EqualTo(3)); + Expect(v.nth(1), InstanceOfType(typeof(IPersistentList))); + IPersistentList sub = v.nth(1) as IPersistentList; + Expect(sub.count(), EqualTo(2)); + } + + [Test] + public void VectorCanContainNestedVector() + { + Object o1 = ReadFromString("[a [b c] d]"); + Expect(o1, InstanceOfType(typeof(IPersistentVector))); + IPersistentVector v = o1 as IPersistentVector; + Expect(v.count(), EqualTo(3)); + Expect(v.nth(1), InstanceOfType(typeof(IPersistentVector))); + IPersistentVector sub = v.nth(1) as IPersistentVector; + Expect(sub.count(), EqualTo(2)); + } + + [Test] + [ExpectedException(typeof(System.IO.EndOfStreamException))] + public void MissingVectorTerminatorFails() + { + Object o1 = ReadFromString("[a b 1 2"); + } + + #endregion + + #region Map tests + + [Test] + public void CanReadBasicMap() + { + Object o1 = ReadFromString("{:abc 12 14 a}"); + Expect(o1, InstanceOfType(typeof(IPersistentMap))); + IPersistentMap m = o1 as IPersistentMap; + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(Keyword.intern(null, "abc")), EqualTo(12)); + Expect(m.valAt(14), EqualTo(Symbol.intern("a"))); + } + + [Test] + public void CanReadEmptyMap() + { + Object o1 = ReadFromString("{ }"); + Expect(o1, InstanceOfType(typeof(IPersistentMap))); + IPersistentMap m = o1 as IPersistentMap; + Expect(m.count(), EqualTo(0)); + } + + + [Test] + [ExpectedException(typeof(System.IO.EndOfStreamException))] + public void MissingRightBraceFails() + { + Object o1 = ReadFromString("{a b 1 2"); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void MapWithOddNumberOfEntriesFails() + { + Object o1 = ReadFromString("{a b 1}"); + } + + + + #endregion + + #region Set tests + + [Test] + public void CanReadBasicSet() + { + Object o1 = ReadFromString("#{abc 12}"); + Expect(o1, InstanceOfType(typeof(IPersistentSet))); + IPersistentSet s = o1 as IPersistentSet; + Expect(s.count(), EqualTo(2)); + Expect(s.contains(Symbol.intern("abc"))); + Expect(s.contains(12)); + } + + [Test] + public void CanReadEmptySet() + { + Object o1 = ReadFromString("#{ }"); + Expect(o1, InstanceOfType(typeof(IPersistentSet))); + IPersistentSet s = o1 as IPersistentSet; + Expect(s.count(), EqualTo(0)); + } + + [Test] + [ExpectedException(typeof(System.IO.EndOfStreamException))] + public void MissingSetTerminatorFails() + { + Object o1 = ReadFromString("#{a b 1 2"); + } + + #endregion + + #region Unmatched delimiter tests + + [Test] + [ExpectedException(typeof(Exception))] + public void NakedRightParenIsBad() + { + Object o1 = ReadFromString("}"); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void NakedRightBracketIsBad() + { + Object o1 = ReadFromString("]"); + } + + + [Test] + [ExpectedException(typeof(Exception))] + public void NakedRightBraceIsBad() + { + Object o1 = ReadFromString("}"); + } + + [Test] + [ExpectedException(typeof(Exception))] + public void MismatchedDelimiterIsBad() + { + Object o1 = ReadFromString("( a b c }"); + } + + #endregion + + #region Wrapping forms + + [Test] + public void QuoteWraps() + { + object o1 = ReadFromString("'a"); + Expect(o1,InstanceOfType(typeof(IPersistentList))); + IPersistentList p = o1 as IPersistentList; + ISeq s = p.seq(); + Expect(s.count(),EqualTo(2)); + Expect(s.first(),EqualTo(Symbol.intern("quote"))); + Expect(s.rest().first(),TypeOf(typeof(Symbol))); + } + + [Test] + public void QuoteWraps2() + { + object o1 = ReadFromString("'(a b c)"); + Expect(o1, InstanceOfType(typeof(IPersistentList))); + IPersistentList p = o1 as IPersistentList; + ISeq s = p.seq(); + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("quote"))); + Expect(s.rest().first(), InstanceOfType(typeof(IPersistentList))); + Expect(((IPersistentList)s.rest().first()).count(), EqualTo(3)); + } + + + [Test] + public void MetaWraps() + { + object o1 = ReadFromString("^a"); + Expect(o1, InstanceOfType(typeof(IPersistentList))); + IPersistentList p = o1 as IPersistentList; + ISeq s = p.seq(); + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("clojure.core","meta"))); + Expect(s.rest().first(), TypeOf(typeof(Symbol))); + } + + [Test] + public void MetaWraps2() + { + object o1 = ReadFromString("^(a b c)"); + Expect(o1, InstanceOfType(typeof(IPersistentList))); + IPersistentList p = o1 as IPersistentList; + ISeq s = p.seq(); + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("clojure.core", "meta"))); + Expect(s.rest().first(), InstanceOfType(typeof(IPersistentList))); + Expect(((IPersistentList)s.rest().first()).count(), EqualTo(3)); + } + + [Test] + public void DerefWraps() + { + object o1 = ReadFromString("@a"); + Expect(o1, InstanceOfType(typeof(IPersistentList))); + IPersistentList p = o1 as IPersistentList; + ISeq s = p.seq(); + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("clojure.core", "deref"))); + Expect(s.rest().first(), TypeOf(typeof(Symbol))); + } + + [Test] + public void DerefWraps2() + { + object o1 = ReadFromString("@(a b c)"); + Expect(o1, InstanceOfType(typeof(IPersistentList))); + IPersistentList p = o1 as IPersistentList; + ISeq s = p.seq(); + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("clojure.core", "deref"))); + Expect(s.rest().first(), InstanceOfType(typeof(IPersistentList))); + Expect(((IPersistentList)s.rest().first()).count(), EqualTo(3)); + } + + #endregion + + #region Syntax-quote tests + + [Test] + public void SQOnSelfEvaluatingReturnsQuotedThing() + { + object o1 = ReadFromString("`:abc"); + object o2 = ReadFromString("`222"); + object o3 = ReadFromString("`\\a)"); + object o4 = ReadFromString("`\"abc\""); + + Expect(o1, TypeOf(typeof(Keyword))); + Expect(o1, EqualTo(Keyword.intern(null, "abc"))); + Expect(o2, TypeOf(typeof(int))); + Expect(o2, EqualTo(222)); + Expect(o3, TypeOf(typeof(char))); + Expect(o3, EqualTo('a')); + Expect(o4, TypeOf(typeof(string))); + Expect(o4, EqualTo("abc")); + } + + [Test] + public void SQOnSpecialFormQuotes() + { + object o1 = ReadFromString("`def"); + Expect(o1,InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + Expect(s.count(),EqualTo(2) ); + Expect(s.first(),EqualTo(Symbol.intern("quote"))); + Expect(s.rest().first(),InstanceOfType(typeof(Symbol))); + Symbol sym = s.rest().first() as Symbol; + Expect(sym.Namespace, Null); + Expect(sym.Name, EqualTo("def")); + } + + [Test] + public void SQOnRegularSymbolResolves() + { + object o1 = ReadFromString("`abc"); + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("quote"))); + Expect(s.rest().first(), InstanceOfType(typeof(Symbol))); + Symbol sym = s.rest().first() as Symbol; + Expect(sym.Namespace, EqualTo(((Namespace)RT.CURRENT_NS.deref()).Name.Name)); + Expect(sym.Name, EqualTo("abc")); + } + + [Test] + public void SQOnGensymGenerates() + { + object o1 = ReadFromString("`abc#"); + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("quote"))); + Expect(s.rest().first(), InstanceOfType(typeof(Symbol))); + Symbol sym = s.rest().first() as Symbol; + Expect(sym.Namespace, Null); + Expect(sym.Name.StartsWith("abc_")); ; + } + + + [Test] + public void SQOnGensymSeesSameTwice() + { + object o1 = ReadFromString("`(abc# abc#)"); + // Return should be + // (clojure/concat (clojure/list (quote abc__N)) + // (clojure/list (quote abc__N)))) + string str = o1.ToString(); + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + Expect(s.count(), EqualTo(3)); + Expect(s.first(), EqualTo(Symbol.intern("clojure.core","concat"))); + + Expect(s.rest().first(), InstanceOfType(typeof(ISeq))); + ISeq s2 = s.rest().first() as ISeq; + Expect(s2.count(), EqualTo(2)); + + Expect(s2.rest().first(), InstanceOfType(typeof(ISeq))); + ISeq s2a = s2.rest().first() as ISeq; + Expect(s2a.rest().first(), InstanceOfType(typeof(Symbol))); + Symbol sym1 = s2a.rest().first() as Symbol; + + Expect(s.rest().rest().first(), InstanceOfType(typeof(ISeq))); + ISeq s3 = s.rest().rest().first() as ISeq; + Expect(s3.count(), EqualTo(2)); + + Expect(s3.rest().first(), InstanceOfType(typeof(ISeq))); + ISeq s3a = s3.rest().first() as ISeq; + Expect(s3a.rest().first(), InstanceOfType(typeof(Symbol))); + Symbol sym2 = s3a.rest().first() as Symbol; + + Expect(sym1.Namespace, Null); + Expect(sym1.Name.StartsWith("abc__")); + Expect(sym1, EqualTo(sym2)); + } + + [Test] + public void SQOnMapMakesMap() + { + Object o1 = ReadFromString("`{:a 1 :b 2}"); + // (clojure/apply + // clojure/hash-map + // (clojure/concat (clojure/list :a) + // (clojure/list 1) + // (clojure/list :b) + // (clojure/list 2))) + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + Expect(s.count(), EqualTo(3)); + Expect(s.first(), EqualTo(Symbol.intern("clojure.core/apply"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("clojure.core/hash-map"))); + Expect(s.rest().rest().first(), InstanceOfType(typeof(ISeq))); + + ISeq s1 = s.rest().rest().first() as ISeq; + ISeq s2; + + Expect(s1.count(), EqualTo(5)); + Expect(s1.first(), EqualTo(Symbol.intern("clojure.core/concat"))); + + s1 = s1.rest(); + Expect(s1.first(),InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(),EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(),EqualTo(Keyword.intern(null,"a"))); + + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(), EqualTo(1)); + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(), EqualTo(Keyword.intern(null, "b"))); + + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(), EqualTo(2)); + } + + public void SQOnVectorMakesVector() + { + Object o1 = ReadFromString("`[:b 2]"); + // (clojure/apply + // clojure/vector + // (clojure/concat (clojure/list :b) + // (clojure/list 2))) + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + Expect(s.count(), EqualTo(3)); + Expect(s.first(), EqualTo(Symbol.intern("clojure.core/apply"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("clojure.core/vector"))); + Expect(s.rest().rest().first(), InstanceOfType(typeof(ISeq))); + + ISeq s1 = s.rest().rest().first() as ISeq; + ISeq s2; + + Expect(s1.count(), EqualTo(3)); + Expect(s1.first(), EqualTo(Symbol.intern("clojure.core/concat"))); + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(), EqualTo(Keyword.intern(null, "b"))); + + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(), EqualTo(2)); + } + + [Test] + public void SQOnSetMakesSet() + { + Object o1 = ReadFromString("`#{:b 2}"); + // (clojure/apply + // clojure/hash-set + // (clojure/concat (clojure/list :b) + // (clojure/list 2))) + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + Expect(s.count(), EqualTo(3)); + Expect(s.first(), EqualTo(Symbol.intern("clojure.core/apply"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("clojure.core/hash-set"))); + Expect(s.rest().rest().first(), InstanceOfType(typeof(ISeq))); + + ISeq s1 = s.rest().rest().first() as ISeq; + + Expect(s1.count(), EqualTo(3)); + Expect(s1.first(), EqualTo(Symbol.intern("clojure.core/concat"))); + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + ISeq s2 = s1.first() as ISeq; + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + ISeq s3 = s1.first() as ISeq; + + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + + + object e1 = s2.rest().first(); + object e2 = s3.rest().first(); + + // Set elements can occur in any order + + Expect(e1, EqualTo(Keyword.intern(null, "b")) | EqualTo(2)); + Expect(e2, EqualTo(Keyword.intern(null, "b")) | EqualTo(2)); + Expect(e1, Not.EqualTo(e2)); + } + + [Test] + public void SQOnListMakesList() + { + Object o1 = ReadFromString("`(:b 2)"); + // (clojure/concat (clojure/list :b) + // (clojure/list 2))) + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s1 = o1 as ISeq; + ISeq s2; + + Expect(s1.count(), EqualTo(3)); + Expect(s1.first(), EqualTo(Symbol.intern("clojure.core/concat"))); + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(), EqualTo(Keyword.intern(null, "b"))); + + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(), EqualTo(2)); + } + + + [Test] + public void UnquoteStandaloneReturnsUnquoteObject() + { + object o1 = ReadFromString("~x"); + + //Expect(o1, InstanceOfType(typeof(LispReader.Unquote))); + //LispReader.Unquote u = o1 as LispReader.Unquote; + //Expect(u.Obj, EqualTo(Symbol.intern("x"))); + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + Expect(s.first(), EqualTo(Symbol.intern("clojure.core/unquote"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("x"))); + Expect(s.count(), EqualTo(2)); + + } + + [Test] + public void UnquoteSpliceStandaloneReturnsUnquoteSpliceObject() + { + object o1 = ReadFromString("~@x"); + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + Expect(s.first(), EqualTo(Symbol.intern("clojure.core/unquote-splicing"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("x"))); + Expect(s.count(), EqualTo(2)); + } + + [Test] + public void SQonUnquoteDequotes() + { + object o1 = ReadFromString("`(a ~b)"); + // (clojure/concat (clojure/list (quote NS/a)) + // (clojure/list b)) + + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s1 = o1 as ISeq; + ISeq s2; + + Expect(s1.count(), EqualTo(3)); + Expect(s1.first(), EqualTo(Symbol.intern("clojure.core/concat"))); + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(), InstanceOfType(typeof(ISeq))); + ISeq s3 = s2.rest().first() as ISeq; + + Expect(s3.count(), EqualTo(2)); + Expect(s3.first(), EqualTo(Symbol.intern("quote"))); + Expect(s3.rest().first(), EqualTo(Symbol.intern(((Namespace)RT.CURRENT_NS.deref()).Name.Name,"a"))); + + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(), EqualTo(Symbol.intern("b"))); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void SQonUnquoteSpliceNotInListFails() + { + object o1 = ReadFromString("`~@x"); + } + + [Test] + public void SqOnUnquoteSpliceSplices() + { + object o1 = ReadFromString("`(a ~@b)"); + // (clojure/concat (clojure/list (quote user/a)) b) + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s1 = o1 as ISeq; + ISeq s2; + + Expect(s1.count(), EqualTo(3)); + Expect(s1.first(), EqualTo(Symbol.intern("clojure.core/concat"))); + + s1 = s1.rest(); + Expect(s1.first(), InstanceOfType(typeof(ISeq))); + + s2 = s1.first() as ISeq; + Expect(s2.first(), EqualTo(Symbol.intern("clojure.core/list"))); + Expect(s2.rest().first(), InstanceOfType(typeof(ISeq))); + ISeq s3 = s2.rest().first() as ISeq; + + Expect(s3.count(), EqualTo(2)); + Expect(s3.first(), EqualTo(Symbol.intern("quote"))); + Expect(s3.rest().first(), EqualTo(Symbol.intern(((Namespace)RT.CURRENT_NS.deref()).Name.Name, "a"))); + + + s1 = s1.rest(); + Expect(s1.first(), EqualTo(Symbol.intern("b"))); + } + + // We should test to see that 'line' meta info is not preserved. + + [Test] + public void SQOnLparenRParenReturnsEmptyList() + { + object o1 = ReadFromString("`()"); + Expect(o1,EqualTo(PersistentList.EMPTY)); + } + + #endregion + + #region #-dispatch tests + + [Test] + [ExpectedException(typeof(Exception))] + public void SharpDispatchOnInvalidCharFails() + { + object o1 = ReadFromString("#a(1 2)"); + } + + #endregion + + #region Meta reader tests + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void MetaOnImproperMetadataFails() + { + object o1 = ReadFromString("#^1 (a b c"); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void MetaOnAppliedToNonIObjFails() + { + object o1 = ReadFromString("#^{:a 1} 7"); + } + + [Test] + public void MetaAppliesHashMetaDataToObject() + { + object o1 = ReadFromString("#^{a 1} (a b)"); + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("a"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("b"))); + + Expect(o1, InstanceOfType(typeof(IObj))); + IObj o = o1 as IObj; + Expect(o.meta(), InstanceOfType(typeof(IPersistentMap))); + IPersistentMap m = o.meta() as IPersistentMap; + + Expect(m.count(), EqualTo(1)); + Expect(m.valAt(Symbol.intern("a")), EqualTo(1)); + } + + + [Test] + public void MetaAppliesSymbolAsTagMetaDataToObject() + { + object o1 = ReadFromString("#^c (a b)"); + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("a"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("b"))); + + Expect(o1, InstanceOfType(typeof(IObj))); + IObj o = o1 as IObj; + Expect(o.meta(), InstanceOfType(typeof(IPersistentMap))); + IPersistentMap m = o.meta() as IPersistentMap; + + Expect(m.count(), EqualTo(1)); + Expect(m.valAt(Keyword.intern(null,"tag")), EqualTo(Symbol.intern("c"))); + } + + [Test] + public void MetaAppliesKeywordAsTagMetaDataToObject() + { + object o1 = ReadFromString("#^:c (a b)"); + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("a"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("b"))); + + Expect(o1, InstanceOfType(typeof(IObj))); + IObj o = o1 as IObj; + Expect(o.meta(), InstanceOfType(typeof(IPersistentMap))); + IPersistentMap m = o.meta() as IPersistentMap; + + Expect(m.count(), EqualTo(1)); + Expect(m.valAt(Keyword.intern(null, "tag")), EqualTo(Keyword.intern(null,"c"))); + } + + [Test] + public void MetaAppliesStringAsTagMetaDataToObject() + { + object o1 = ReadFromString("#^\"help\" (a b)"); + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("a"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("b"))); + + Expect(o1, InstanceOfType(typeof(IObj))); + IObj o = o1 as IObj; + Expect(o.meta(), InstanceOfType(typeof(IPersistentMap))); + IPersistentMap m = o.meta() as IPersistentMap; + + Expect(m.count(), EqualTo(1)); + Expect(m.valAt(Keyword.intern(null, "tag")), EqualTo("help")); + } + + [Test] + public void MetaAddsLineupNumberAsMetaDataIfAvailable() + { + object o1 = ReadFromStringNumbering("\n\n#^:c (a b)"); + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("a"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("b"))); + + Expect(o1, InstanceOfType(typeof(IObj))); + IObj o = o1 as IObj; + Expect(o.meta(), InstanceOfType(typeof(IPersistentMap))); + IPersistentMap m = o.meta() as IPersistentMap; + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(Keyword.intern(null, "tag")), EqualTo(Keyword.intern(null,"c"))); + Expect(m.valAt(Keyword.intern(null, "line")), EqualTo(3)); + } + + #endregion + + #region Var reader tests + + [Test] + public void VarWrapsVar() + { + Object o1 = ReadFromString("#'abc"); + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(Symbol.intern("var"))); + Expect(s.rest().first(), EqualTo(Symbol.intern("abc"))); + } + + #endregion + + #region Regex reader tests + + [Test] + public void SharpDoubleQuoteGeneratesRegex() + { + object o1 = ReadFromString("#\"abc\""); + + Expect(o1, InstanceOfType(typeof(System.Text.RegularExpressions.Regex))); + System.Text.RegularExpressions.Regex r = o1 as System.Text.RegularExpressions.Regex; + Expect(r.ToString(), EqualTo("abc")); + } + + [Test] + [ExpectedException(typeof(System.IO.EndOfStreamException))] + public void SharpDQHitsEOFFails() + { + object o1 = ReadFromString("#\"abc"); + } + + [Test] + public void SharpDQEscapesOnBackslash() + { + char[] chars = new char[] { + '#', '"', 'a', '\\', '"', 'b', 'c', '"' + }; + + // input = #"a\"bc" -- should go over the " + + string str = new String(chars); + + object o1 = ReadFromString(str); + + Expect(o1, InstanceOfType(typeof(System.Text.RegularExpressions.Regex))); + System.Text.RegularExpressions.Regex r = o1 as System.Text.RegularExpressions.Regex; + Expect(r.ToString(), EqualTo("a\\\"bc")); + } + + #endregion + + #region Fn reader & Arg reader tests + + [Test] + public void SharpFnWithNoArgsGeneratesNoArgFn() + { + object o1 = ReadFromString("#(+ 1 2)"); + // (fn* [] (+ 1 2)) + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + + Expect(s.first(), EqualTo(Symbol.intern("fn*"))); + s = s.rest(); + Expect(s.first(), InstanceOfType(typeof(IPersistentVector))); + IPersistentVector arglist = s.first() as IPersistentVector; + + Expect(arglist.count(), EqualTo(0)); + + s = s.rest(); + Expect(s.first(), InstanceOfType(typeof(ISeq))); + Expect(s.rest(), Null); + + ISeq form = s.first() as ISeq; + + Expect(form.count(), EqualTo(3)); + Expect(form.first(), EqualTo(Symbol.intern("+"))); + Expect(form.rest().first(), EqualTo(1)); + Expect(form.rest().rest().first(), EqualTo(2)); + } + + [Test] + public void SharpFnWithArgsGeneratesFnWithArgs() + { + object o1 = ReadFromString("#(+ %2 2)"); + // (fn* [p1__N p2__M] (+ p2__M 2)) + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + + Expect(s.first(), EqualTo(Symbol.intern("fn*"))); + s = s.rest(); + Expect(s.first(), InstanceOfType(typeof(IPersistentVector))); + IPersistentVector arglist = s.first() as IPersistentVector; + + Expect(arglist.count(), EqualTo(2)); + Expect(arglist.nth(0), InstanceOfType(typeof(Symbol))); + Expect(arglist.nth(1), InstanceOfType(typeof(Symbol))); + Symbol arg1 = arglist.nth(0) as Symbol; + Symbol arg2 = arglist.nth(1) as Symbol; + Expect(arg1.Name, StartsWith("p1__")); + Expect(arg2.Name, StartsWith("p2__")); + + s = s.rest(); + Expect(s.first(), InstanceOfType(typeof(ISeq))); + Expect(s.rest(), Null); + + ISeq form = s.first() as ISeq; + + Expect(form.count(), EqualTo(3)); + Expect(form.first(), EqualTo(Symbol.intern("+"))); + Expect(form.rest().first(), EqualTo(arg2)); + Expect(form.rest().rest().first(), EqualTo(2)); + } + + [Test] + public void SharpFnWithRestArgGeneratesFnWithRestArg() + { + object o1 = ReadFromString("#(+ %2 %&)"); + // (fn* [p1__N p2__M & rest__X] (+ p2__M rest__X)) + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + + Expect(s.first(), EqualTo(Symbol.intern("fn*"))); + s = s.rest(); + Expect(s.first(), InstanceOfType(typeof(IPersistentVector))); + IPersistentVector arglist = s.first() as IPersistentVector; + + Expect(arglist.count(), EqualTo(4)); + Expect(arglist.nth(0), InstanceOfType(typeof(Symbol))); + Expect(arglist.nth(1), InstanceOfType(typeof(Symbol))); + Expect(arglist.nth(2), InstanceOfType(typeof(Symbol))); + Expect(arglist.nth(3), InstanceOfType(typeof(Symbol))); + Symbol arg1 = arglist.nth(0) as Symbol; + Symbol arg2 = arglist.nth(1) as Symbol; + Symbol arg3 = arglist.nth(2) as Symbol; + Symbol arg4 = arglist.nth(3) as Symbol; + Expect(arg1.Name, StartsWith("p1__")); + Expect(arg2.Name, StartsWith("p2__")); + Expect(arg3.Name, EqualTo("&")); + Expect(arg4.Name, StartsWith("rest__")); + + s = s.rest(); + Expect(s.first(), InstanceOfType(typeof(ISeq))); + Expect(s.rest(), Null); + + ISeq form = s.first() as ISeq; + + Expect(form.count(), EqualTo(3)); + Expect(form.first(), EqualTo(Symbol.intern("+"))); + Expect(form.rest().first(), EqualTo(arg2)); + Expect(form.rest().rest().first(), EqualTo(arg4)); + } + + [Test] + public void SharpFnWithAnonArgGeneratesFnWithArgs() + { + object o1 = ReadFromString("#(+ % 2)"); + // (fn* [p1__N] (+ p1__N 2)) + + Expect(o1, InstanceOfType(typeof(ISeq))); + ISeq s = o1 as ISeq; + + Expect(s.first(), EqualTo(Symbol.intern("fn*"))); + s = s.rest(); + Expect(s.first(), InstanceOfType(typeof(IPersistentVector))); + IPersistentVector arglist = s.first() as IPersistentVector; + + Expect(arglist.count(), EqualTo(1)); + Expect(arglist.nth(0), InstanceOfType(typeof(Symbol))); + Symbol arg1 = arglist.nth(0) as Symbol; + Expect(arg1.Name, StartsWith("p1__")); + + s = s.rest(); + Expect(s.first(), InstanceOfType(typeof(ISeq))); + Expect(s.rest(), Null); + + ISeq form = s.first() as ISeq; + + Expect(form.count(), EqualTo(3)); + Expect(form.first(), EqualTo(Symbol.intern("+"))); + Expect(form.rest().first(), EqualTo(arg1)); + Expect(form.rest().rest().first(), EqualTo(2)); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ArgReaderOutsideSharpFnFails() + { + object o1 = ReadFromString("(+ %2 2)"); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ArgReaderFollowedByNonNumericFails() + { + object o1 = ReadFromString("#(+ %a 2)"); + } + + + + #endregion + + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/LockingTransactionTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/LockingTransactionTests.cs new file mode 100644 index 00000000..23682559 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/LockingTransactionTests.cs @@ -0,0 +1,194 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; +using System.Threading; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add tests for LockingTransaction + [TestFixture] + public class LockingTransactionTests : AssertionHelper + { + + + //// TODO: Make this work. + + //// This test is taken from the Java code. + //[Test] + //public void BigTest() + //{ + // // We have to start the main work unit on its own thread because + // // the main during testing is STA and so does not support waiting on multiple handles. + + // BigTester tester = new BigTester(5, 10, 2000); + // EventWaitHandle h = new EventWaitHandle(false, EventResetMode.ManualReset); + // Thread t = new Thread(tester.Work); + // t.Start(h); + // h.WaitOne(); + // Console.WriteLine("Done"); + //} + + //class BigTester where T : LockingTransactionTests.RefTester + //{ + // int _nthreads; + // int _niters; + // int _nitems; + + // public BigTester(int nthreads, int nitems, int niters) + // { + // _nthreads = nthreads; + // _nitems = nitems; + // _niters = niters; + // } + + // public void Work(object o) + // { + // List refs = new List(); + + // for (int i = 0; i < _nitems; i++) + // refs.Add(new Ref(0)); + + // List threads = new List(_nthreads); + // List handles = new List(_nthreads); + // List tasks = new List(_nthreads); + + // for (int i = 0; i < _nthreads; i++) + // { + // List copy = refs.GetRange(0, refs.Count); + // Shuffle(copy); + // tasks.Add(new Incrementer(i, _niters, copy)); + // threads.Add(new Thread(tasks[i].Work)); + // handles.Add(new EventWaitHandle(false, EventResetMode.ManualReset)); + // } + + + // for (int i = 0; i < _nthreads; i++) + // { + // threads[i].Name = "Thr " + i; + // threads[i].Start(handles[i]); + // } + + // EventWaitHandle.WaitAll(handles.ToArray()); + + // foreach (Incrementer task in tasks) + // Console.WriteLine("Task {0}: {1} millisecs", task.Id, task.Nanos / 10000.0); + + // foreach (Ref r in refs) + // Console.WriteLine("Ref is {0}", r.get()); + + // EventWaitHandle ewh = (EventWaitHandle)o; + // ewh.Set(); + + // } + + + // void Shuffle(List refs) + // { + // } + //} + + //public abstract class RefTester + //{ + // readonly int _id; + // public int Id + // { + // get { return _id; } + // } + + // protected readonly int _niters; + // protected readonly List _items; + + // long _nanos = 0; + // public long Nanos + // { + // get { return _nanos; } + // } + + + // public RefTester(int id, int niters, List items) + // { + // _id = id; + // _niters = niters; + // _items = items; + // } + + // public void Work(object o) + // { + // for (int i = 0; i < _niters; i++) + // { + // long startTime = DateTime.Now.Ticks; + // LockingTransaction.runInTransaction(this.TxUnit); + // long finishTime = DateTime.Now.Ticks; + // _nanos += finishTime - startTime; + // } + + // EventWaitHandle h = (EventWaitHandle)o; + // h.Set(); + // } + + // public abstract object TxUnit(object[] args); + //} + + //class Incrementer : RefTester + //{ + // public Incrementer(int id, int niters, List items) + // : base(id, niters, items) + // { + // } + + // public override object TxUnit(object[] args) + // { + // foreach (Ref r in _items) + // { + // int val = (int)r.get(); + // r.set(val + 1); + // } + // return null; + // } + //} + + + //class Commuter : RefTester + //{ + // public Commuter(int id, int niters, List items) + // : base(id, niters, items) + // { + // } + + // public override object TxUnit(object[] args) + // { + // foreach (Ref r in _items) + // { + // r.commute(Commuter.Incr,null); + // } + // return null; + // } + + // static object Incr(object[] args) + // { + // int val = (int)args[0]; + // return val + 1; + // } + //} + + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/MapEntryTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/MapEntryTests.cs new file mode 100644 index 00000000..2a5253fb --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/MapEntryTests.cs @@ -0,0 +1,369 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class MapEntryTests : AssertionHelper + { + #region C-tor tests + + [Test] + public void CtorCreatesEntryWithProperKeyVal() + { + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.key(), EqualTo(1)); + Expect(me.val(), EqualTo("abc")); + } + + #endregion + + #region Object override tests + + [Test] + public void HashCodeSameAsPersistentVector() + { + MapEntry me = new MapEntry(1, "abc"); + PersistentVector v = PersistentVector.create(1, "abc"); + + Expect(me.GetHashCode(), EqualTo(v.GetHashCode())); + } + + [Test] + public void HashCodeFalseOnDifferentValues() + { + MapEntry me = new MapEntry(1, "abc"); + PersistentVector v = PersistentVector.create(1, "abcd"); + + Expect(me.GetHashCode(), Not.EqualTo(v.GetHashCode())); + } + + [Test] + public void EqualsWorksOnPersistentVector() + { + MapEntry me = new MapEntry(1, "abc"); + PersistentVector v = PersistentVector.create(1, "abc"); + + Expect(me.Equals(v)); + } + + [Test] + public void EqualsWorksFalseOnDifferentValues() + { + MapEntry me = new MapEntry(1, "abc"); + PersistentVector v = PersistentVector.create(1, "abcd"); + + Expect(me.Equals(v),False); + } + + + #endregion + + #region IMapEntry tests + + #endregion + + #region IPersistentVector tests + + [Test] + public void LengthIs2() + { + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.length(), EqualTo(2)); + } + + [Test] + public void NthInRangeWorks() + { + + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.nth(0), EqualTo(1)); + Expect(me.nth(1), EqualTo("abc")); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void NthOutOfRangeLowFails() + { + MapEntry me = new MapEntry(1, "abc"); + object obj = me.nth(-4); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void NthOutOfRangeHighFails() + { + MapEntry me = new MapEntry(1, "abc"); + object obj = me.nth(4); + } + + [Test] + public void AssocNInRangeModifies() + { + MapEntry me = new MapEntry(1, "abc"); + IPersistentVector v1 = me.assocN(0, 2); + IPersistentVector v2 = me.assocN(1, "def"); + IPersistentVector v3 = me.assocN(2, "ghi"); + + Expect(me.count(), EqualTo(2)); + Expect(me.key(), EqualTo(1)); + Expect(me.val(), EqualTo("abc")); + + Expect(v1.count(), EqualTo(2)); + Expect(v1.nth(0), EqualTo(2)); + Expect(v1.nth(1), EqualTo("abc")); + + Expect(v2.count(), EqualTo(2)); + Expect(v2.nth(0), EqualTo(1)); + Expect(v2.nth(1), EqualTo("def")); + + Expect(v3.count(), EqualTo(3)); + Expect(v3.nth(0), EqualTo(1)); + Expect(v3.nth(1), EqualTo("abc")); + Expect(v3.nth(2), EqualTo("ghi")); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void AssocNOutOfRangeLowThrows() + { + MapEntry me = new MapEntry(1, "abc"); + IPersistentVector v1 = me.assocN(-4, 2); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void AssocNOutOfRangeHighThrows() + { + MapEntry me = new MapEntry(1, "abc"); + IPersistentVector v1 = me.assocN(4, 2); + } + + [Test] + public void ConsWorks() + { + MapEntry me = new MapEntry(1, "abc"); + IPersistentVector v1 = me.cons(2); + + Expect(me.count(), EqualTo(2)); + Expect(me.key(), EqualTo(1)); + Expect(me.val(), EqualTo("abc")); + + + Expect(v1.count(), EqualTo(3)); + Expect(v1.nth(0), EqualTo(1)); + Expect(v1.nth(1), EqualTo("abc")); + Expect(v1.nth(2), EqualTo(2)); + } + + #endregion + + #region Associative tests + + [Test] + public void ContainsKeyOnExistingKeyWorks() + { + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.containsKey(0)); + Expect(me.containsKey(1)); + } + + [Test] + public void ContainsKeyOutOfRangeIsFalse() + { + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.containsKey(-4),False); + Expect(me.containsKey(4), False); + } + + + [Test] + public void EntryAtOnExistingKeyWorks() + { + MapEntry me = new MapEntry(1, "abc"); + IMapEntry me1 = me.entryAt(0); + IMapEntry me2 = me.entryAt(1); + + Expect(me1.key(), EqualTo(0)); + Expect(me1.val(), EqualTo(1)); + Expect(me2.key(), EqualTo(1)); + Expect(me2.val(), EqualTo("abc")); + } + + [Test] + public void EntryAtOutOfRangeLowReturnsNull() + { + MapEntry me = new MapEntry(1, "abc"); + IMapEntry me1 = me.entryAt(-4); + + Expect(me1,Null); + } + + [Test] + public void EntryAtOutOfRangeHighReturnsNull() + { + MapEntry me = new MapEntry(1, "abc"); + IMapEntry me1 = me.entryAt(4); + + Expect(me1, Null); + } + + [Test] + public void ValAtOnExistingKeyReturnsValue() + { + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.valAt(0), EqualTo(1)); + Expect(me.valAt(1), EqualTo("abc")); + } + + [Test] + public void ValAtOnMissingKeyReturnsNull() + { + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.valAt(-4), Null); + Expect(me.valAt(4), Null); + } + + [Test] + public void ValAtWithDefaultOnExistingKeyReturnsValue() + { + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.valAt(0,7), EqualTo(1)); + Expect(me.valAt(1,7), EqualTo("abc")); + } + + [Test] + public void ValAtWithDefaultOnMissingKeyReturnsDefault() + { + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.valAt(-4,7), EqualTo(7)); + Expect(me.valAt(4, 7), EqualTo(7)); + } + + #endregion + + #region Reversible tests + + [Test] + public void RseqReturnReverseSeq() + { + MapEntry me = new MapEntry(1, "abc"); + + ISeq s = me.rseq(); + + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo("abc")); + Expect(s.rest().first(), EqualTo(1)); + Expect(s.rest().rest(), Null); + } + + #endregion + + #region IPersistentCollection tests + + [Test] + public void CountIs2() + { + MapEntry me = new MapEntry(1, "abc"); + Expect(me.count(), EqualTo(2)); + } + + [Test] + public void SeqReturnsASeq() + { + MapEntry me = new MapEntry(1, "abc"); + ISeq s = me.seq(); + + Expect(s.count(), EqualTo(2)); + Expect(s.first(), EqualTo(1)); + Expect(s.rest().first(), EqualTo("abc")); + Expect(s.rest().rest(), Null); + } + + [Test] + public void EmptyReutrnsNull() + { + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.empty(), Null); + } + + + [Test] + public void ExplictIPersistentCollectionConsWorks() + { + MapEntry me = new MapEntry(1, "abc"); + IPersistentCollection c = (IPersistentCollection)me; + ISeq s = c.cons(2).seq(); + + Expect(me.count(), EqualTo(2)); + Expect(me.key(), EqualTo(1)); + Expect(me.val(), EqualTo("abc")); + + Expect(s.count(), EqualTo(3)); + Expect(s.first(), EqualTo(1)); + Expect(s.rest().first(), EqualTo("abc")); + Expect(s.rest().rest().first(), EqualTo(2)); + Expect(s.rest().rest().rest(), Null); + } + + #endregion + + #region IPersistentStack tests + + [Test] + public void PeekReturnsVal() + { + MapEntry me = new MapEntry(1, "abc"); + + Expect(me.peek(), EqualTo("abc")); + Expect(me.count(), EqualTo(2)); + Expect(me.key(), EqualTo(1)); + Expect(me.val(), EqualTo("abc")); + } + + [Test] + public void PopLosesTheValue() + { + MapEntry me = new MapEntry(1, "abc"); + IPersistentVector v = (IPersistentVector)me.pop(); + + Expect(v.length(), EqualTo(1)); + Expect(v.nth(0), EqualTo(1)); + } + + + + + #endregion + + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/NamespaceTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/NamespaceTests.cs new file mode 100644 index 00000000..4e6fcbab --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/NamespaceTests.cs @@ -0,0 +1,257 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + + +namespace Clojure.Tests.LibTests +{ + + //TODO: NEed to fix NS tests to clear the created namespaces after each test. + /* + [TestFixture] + public class NamespaceTests : AssertionHelper + { + #region C-tor tests + + [Test] + public void FindOrCreateCreatesANewNamespace() + { + Symbol sym = Symbol.intern("abc"); + Namespace ns = Namespace.findOrCreate(sym); + + Expect(ns, Not.Null); + Expect(ns.Name, EqualTo(sym)); + } + + [Test] + public void FindOrCreateFindsExistingNamespace() + { + Symbol sym1 = Symbol.intern("abc"); + Namespace ns1 = Namespace.findOrCreate(sym1); + Symbol sym2 = Symbol.intern("abc"); + Namespace ns2 = Namespace.findOrCreate(sym2); + + Expect(Object.ReferenceEquals(ns1, ns2)); + } + + [Test] + public void FindGivesNullOnMissingNS() + { + Symbol sym = Symbol.intern("abc"); + Namespace ns = Namespace.find(sym); + + Expect(ns, Null); + } + + [Test] + public void FindFindsExistingNS() + { + Symbol sym1 = Symbol.intern("abc"); + Namespace ns1 = Namespace.findOrCreate(sym1); + Symbol sym2 = Symbol.intern("abc"); + Namespace ns2 = Namespace.find(sym2); + + Expect(Object.ReferenceEquals(ns1, ns2)); + } + + [Test] + public void RemoveRemovesExisingNamespace() + { + Symbol sym1 = Symbol.intern("abc"); + Namespace ns1 = Namespace.findOrCreate(sym1); + Symbol sym2 = Symbol.intern("abc"); + Namespace ns2 = Namespace.remove(sym2); + Namespace ns3 = Namespace.find(sym1); + + Expect(object.ReferenceEquals(ns1, ns2)); + Expect(ns3, Null); + } + + + [Test] + public void RemoveReturnsNullOnNonExisingNamespace() + { + Symbol sym2 = Symbol.intern("abc"); + Namespace ns2 = Namespace.remove(sym2); + + Expect(ns2, Null); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void RemoveFailsRemovingClojureCoreNS() + { + Symbol sym = Symbol.intern("clojure.core"); + Namespace ns = Namespace.remove(sym); + } + + + // how to test the thread-safety of findOrCreatea? + + #endregion + + #region object override tests + + [Test] + public void ToStringWorks() + { + // do we care all that much? + Namespace ns = Namespace.findOrCreate(Symbol.intern("abc")); + Expect(ns.ToString(),EqualTo("#")); + } + + #endregion + + #region Interning symbols tests + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void InterningSymbolWithNamespaceFails() + { + Symbol sym = Symbol.intern("abc", "def"); + Namespace ns = Namespace.findOrCreate(Symbol.intern("ghi")); + Var v = ns.intern(sym); + } + + [Test] + public void InterningSymbolCreatesVar() + { + Symbol sym = Symbol.intern("def"); + Namespace ns = Namespace.findOrCreate(Symbol.intern("abc")); + + Var v = ns.intern(sym); + + Expect(v, Not.Null); + Expect(v.Namespace, EqualTo(ns)); + + } + + [Test] + public void InterningSymbolEntersVarInMap() + { + Symbol sym = Symbol.intern("def"); + Namespace ns = Namespace.findOrCreate(Symbol.intern("abc")); + + Var v = ns.intern(sym); + + Expect(ns.findInternedVar(sym), SameAs(v)); + } + + + + [Test] + public void InterningSymbolAgainFindsVar() + { + Symbol sym = Symbol.intern("def"); + Namespace ns = Namespace.findOrCreate(Symbol.intern("abc")); + + Var v1 = ns.intern(sym); + + Var v2 = ns.intern(sym); + + Expect(Object.ReferenceEquals(v1, v2)); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ReferSymbolToVarInOtherAndThenInterningThrows() + { + // I don't know why + + Namespace ns1 = Namespace.findOrCreate(Symbol.intern("abc")); + + Symbol sym1 = Symbol.intern("def"); + Var v1 = ns1.intern(sym1); + + Namespace ns2 = Namespace.findOrCreate(Symbol.intern("d")); + Symbol sym2 = Symbol.intern("g"); + + ns2.refer(sym2, v1); + ns2.intern(sym2); + } + + + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ReferOfSymbolWithNamespaceFails() + { + Symbol sym = Symbol.intern("abc", "def"); + Namespace ns = Namespace.findOrCreate(Symbol.intern("ghi")); + ns.refer(sym, Var.create()); + } + + [Test] + public void ReferEntersVar() + { + Namespace ns = Namespace.findOrCreate(Symbol.intern("abc")); + + Symbol sym = Symbol.intern("def"); + Var v = Var.create(); + ns.refer(sym, v); + + Expect(ns.getMapping(sym), SameAs(v)); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ImportTypeOnSymbolWithNamespaceFails() + { + Symbol sym = Symbol.intern("abc", "def"); + Namespace ns = Namespace.findOrCreate(Symbol.intern("ghi")); + ns.importType(sym, typeof(Int32)); + } + + [Test] + public void ImportTypeEntersType() + { + Namespace ns = Namespace.findOrCreate(Symbol.intern("abc")); + + Symbol sym = Symbol.intern("def"); + ns.importType(sym, typeof(Int32)); + + Expect(ns.getMapping(sym), SameAs(typeof(Int32))); + } + + + [Test] + public void FindInternedVarFailsIfNonVarValueInMap() + { + Namespace ns = Namespace.findOrCreate(Symbol.intern("abc")); + + Symbol sym = Symbol.intern("def"); + ns.importType(sym, typeof(Int32)); + + Var v = ns.findInternedVar(sym); + + Expect(v, Null); + } + + + // Don't know how to test the race condition in the loops for + // intern(Symbol), reference(Symbol), unmap(Symbol) + + #endregion + } + */ + +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/NumbersTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/NumbersTests.cs new file mode 100644 index 00000000..e5c869fc --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/NumbersTests.cs @@ -0,0 +1,137 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; +using java.math; + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class NumbersTests : AssertionHelper + { + #region Helpers + + private void ExpectInt32(object x) + { + Expect(x, TypeOf(typeof(Int32))); + } + + private void ExpectSameObject(object x, object y) + { + Expect(x, SameAs(y)); + } + + private void ExpectEqualObject(object x, object y) + { + Expect(x, EqualTo(y)); + } + + #endregion + + #region reduce tests + + [Test] + public void ReduceOnBigIntReducesSmallerValues() + { + BigInteger b1 = new BigInteger("123"); + BigInteger b2 = new BigInteger("0"); + BigInteger b3 = new BigInteger(Int32.MaxValue.ToString()); + BigInteger b4 = new BigInteger(Int32.MinValue.ToString()); + + ExpectInt32(Numbers.reduce(b1)); + ExpectInt32(Numbers.reduce(b2)); + ExpectInt32(Numbers.reduce(b3)); + ExpectInt32(Numbers.reduce(b4)); + } + + [Test] + public void ReduceOnBigIntReturnsLargerValues() + { + BigInteger b1 = new BigInteger("100000000000000000000", 16); + BigInteger b2 = b1.negate(); + BigInteger b3 = new BigInteger("123456789012345678901234567890"); + BigInteger b4 = b3.negate(); + + ExpectSameObject(b1, Numbers.reduce(b1)); + ExpectSameObject(b2, Numbers.reduce(b2)); + ExpectSameObject(b3, Numbers.reduce(b3)); + ExpectSameObject(b4, Numbers.reduce(b4)); + } + + [Test] + public void ReduceOnLongReducesSmallerValues() + { + long b1 = 123; + long b2 = 0; + long b3 = Int32.MaxValue; + long b4 = Int32.MinValue; + + ExpectInt32(Numbers.reduce(b1)); + ExpectInt32(Numbers.reduce(b2)); + ExpectInt32(Numbers.reduce(b3)); + ExpectInt32(Numbers.reduce(b4)); + } + + + [Test] + public void ReduceOnLongReturnsLargerValues() + { + long b1 = ((long)Int32.MaxValue) + 1; + long b2 = ((long)Int32.MinValue) - 1; + long b3 = 123456789000; + long b4 = -b3; + + ExpectEqualObject(b1, Numbers.reduce(b1)); + ExpectEqualObject(b2, Numbers.reduce(b2)); + ExpectEqualObject(b3, Numbers.reduce(b3)); + ExpectEqualObject(b4, Numbers.reduce(b4)); + } + + #endregion + + #region divide tests + + [Test] + [ExpectedException(typeof(ArithmeticException))] + public void DivideByZeroFails() + { + object o = Numbers.BIDivide(Numbers.BigIntegerOne, Numbers.BigIntegerZero); + } + + [Test] + public void DivideReducesToIntOnDenomOne() + { + object o = Numbers.BIDivide(new BigInteger("75"), new BigInteger("25")); + Expect(o, EqualTo(3)); + } + + [Test] + public void DivideReturnsReducedRatio() + { + object o = Numbers.BIDivide(new BigInteger("42"), new BigInteger("30")); + + Expect(o, TypeOf(typeof(Ratio))); + + Ratio r = o as Ratio; + Expect(r.Numerator, EqualTo(new BigInteger("7"))); + Expect(r.Denominator, EqualTo(new BigInteger("5"))); + } + + #endregion + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/ObjTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ObjTests.cs new file mode 100644 index 00000000..bf7423ba --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/ObjTests.cs @@ -0,0 +1,68 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class ObjTests : IObjTests + { + + class MockObj : Obj + { + public MockObj() + { + } + + public MockObj(IPersistentMap meta) + : base(meta) + { + } + + public override IObj withMeta(IPersistentMap meta) + { + return meta == _meta + ? this + : new MockObj(meta); + } + } + + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + _objWithNullMeta = new MockObj(); + _obj = new MockObj(meta); + _expectedType = typeof(MockObj); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + } +} + diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentArrayMapTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentArrayMapTests.cs new file mode 100644 index 00000000..87692146 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentArrayMapTests.cs @@ -0,0 +1,917 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using System.Collections; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class PersistentArrayMapTests : AssertionHelper + { + #region C-tor tests + + [Test] + public void CreateOnEmptyDictionaryReturnsEmptyMap() + { + Dictionary d = new Dictionary(); + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.count(), EqualTo(0)); + } + + [Test] + public void CreateOnDictionaryReturnsMap() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + Expect(m.containsKey(3), False); + } + + // other c-tors are not public. + + + #endregion + + #region Associative tests + + [Test] + public void ContainsKeyOnMissingKeyIsFalse() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.containsKey(3), False); + } + + + [Test] + public void ContainsKeyOnExistingKeyIsTrue() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.containsKey(1)); + Expect(m.containsKey(2)); + } + + [Test] + public void ContainsKeyNotConfusedByValue() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.containsKey("a"), False); + } + + [Test] + public void EntryAtReturnsNullOnMissingKey() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.entryAt(3), Null); + } + + [Test] + public void EntryAtReturnsEntryforKey() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + IMapEntry me = m.entryAt(1); + + Expect(me.key(), EqualTo(1)); + Expect(me.val(), EqualTo("a")); + } + + [Test] + public void ValAt1ReturnsNullOnMissingKey() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.valAt(3), Null); + } + + [Test] + public void ValAt1ReturnsValueforKey() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.valAt(1), EqualTo("a")); + } + + + [Test] + public void ValAt2ReturnsDefaultOnMissingKey() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.valAt(3,99), EqualTo(99)); + } + + [Test] + public void ValAt2ReturnsValueforKey() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.valAt(1,99), EqualTo("a")); + } + + #endregion + + #region IPersistentCollection tests + + [Test] + public void CountOnEmptyReturns0() + { + Dictionary d = new Dictionary(); + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.count(), EqualTo(0)); + } + + [Test] + public void CountOnNonEmptyReturnsCount() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.count(), EqualTo(2)); + } + + [Test] + public void EmptyReturnsEmpty() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + IPersistentMap m = PersistentArrayMap.create(d); + IPersistentCollection c = m.empty(); + + Expect(c.count(), EqualTo(0)); + Expect(c.seq(), Null); + } + + + [Test] + public void SeqOnEmptyReturnNull() + { + Dictionary d = new Dictionary(); + IPersistentMap m = PersistentArrayMap.create(d); + ISeq s = m.seq(); + + Expect(s, Null); + } + + [Test] + public void SeqOnNonEmptyIterates() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + IPersistentMap m = PersistentArrayMap.create(d); + ISeq s = m.seq(); + IMapEntry me1 = (IMapEntry)s.first(); + IMapEntry me2 = (IMapEntry)s.rest().first(); + ISeq end = s.rest().rest(); + + Expect(s.count(), EqualTo(2)); + Expect(me1.key(), EqualTo(1) | EqualTo(2)); + Expect(me1.val(), EqualTo(((int)me1.key()==1 ? "a" : "b"))); + Expect(me2.key(), EqualTo(1) | EqualTo(2)); + Expect(me2.val(), EqualTo(((int)me2.key() == 1 ? "a" : "b"))); + Expect(end, Null); + } + + #endregion + + #region IPersistentMap tests + + [Test] + public void AssocModifiesOnExistingKey() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m1 = PersistentArrayMap.create(d); + IPersistentMap m2 = m1.assoc(2, "c"); + + Expect(m1.count(), EqualTo(2)); + Expect(m1.valAt(2), EqualTo("b")); + Expect(m2.count(), EqualTo(2)); + Expect(m2.valAt(2), EqualTo("c")); + } + + + [Test] + public void AssocAddsOnNewKey() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m1 = PersistentArrayMap.create(d); + IPersistentMap m2 = m1.assoc(3, "c"); + + Expect(m1.count(), EqualTo(2)); + Expect(m1.containsKey(3), False); + Expect(m2.count(), EqualTo(3)); + Expect(m2.valAt(3), EqualTo("c")); + } + + + [Test] + [ExpectedException(typeof(Exception))] + public void AssocExFailsOnExistingKey() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m1 = PersistentArrayMap.create(d); + IPersistentMap m2 = m1.assocEx(2, "c"); + } + + + + [Test] + public void AssocExModifiesOnNewKey() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m1 = PersistentArrayMap.create(d); + IPersistentMap m2 = m1.assocEx(3, "c"); + + Expect(m1.count(), EqualTo(2)); + Expect(m1.containsKey(3), False); + Expect(m2.count(), EqualTo(3)); + Expect(m2.valAt(3), EqualTo("c")); + } + + [Test] + public void WithoutOnExistingKeyRemovesKey() + { + Dictionary d = new Dictionary(); + d[3] = "a"; + d[5] = "b"; + d[7] = "c"; + + IPersistentMap m1 = PersistentArrayMap.create(d); + IPersistentMap m2 = m1.without(5); + + Expect(m1.count(), EqualTo(3)); + Expect(m1.valAt(5), EqualTo("b")); + Expect(m2.count(), EqualTo(2)); + Expect(m2.containsKey(5), False); + } + + [Test] + public void WithoutOnMissingKeyIsIdentity() + { + Dictionary d = new Dictionary(); + d[3] = "a"; + d[5] = "b"; + d[7] = "c"; + + IPersistentMap m1 = PersistentArrayMap.create(d); + IPersistentMap m2 = m1.without(4); + + Expect(m2, SameAs(m1)); + } + + #endregion + + #region APersistentMap tests + + [Test] + public void EqualsOnSimilarDictionaryReturnsTrue() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + Expect(m.equiv(d)); + } + + [Test] + public void EqualsOnDictionaryWIthDifferntValueReturnsFalse() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + d[2] = "c"; + + Expect(m.Equals(d),False); + } + + + [Test] + public void EqualsOnDictionaryWithExtraValueReturnsFalse() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + d[3] = "c"; + + Expect(m.Equals(d), False); + } + + [Test] + public void HashCodeBasedOnValue() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m1 = PersistentArrayMap.create(d); + + d[3] = "c"; + IPersistentMap m2 = PersistentArrayMap.create(d); + + Expect(m1.GetHashCode(), Not.EqualTo(m2.GetHashCode())); + } + + [Test] + public void AssociativeDotAssocWorks() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + Associative a = (Associative)m; + + Associative a1 = a.assoc(3, "c"); + Associative a2 = a.assoc(2, "c"); + + Expect(a.count(), EqualTo(2)); + Expect(a.valAt(1), EqualTo("a")); + Expect(a.valAt(2), EqualTo("b")); + Expect(a.containsKey(3), False); + + Expect(a1.count(), EqualTo(3)); + Expect(a1.valAt(1), EqualTo("a")); + Expect(a1.valAt(2), EqualTo("b")); + Expect(a1.valAt(3), EqualTo("c")); + + Expect(a2.count(), EqualTo(2)); + Expect(a2.valAt(1), EqualTo("a")); + Expect(a2.valAt(2), EqualTo("c")); + Expect(a2.containsKey(3), False); + } + + [Test] + public void ConsOnIMapEntryAddsNew() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + IPersistentMap c = m.cons(new MapEntry(3, "c")); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + + Expect(c.count(), EqualTo(3)); + Expect(c.valAt(1), EqualTo("a")); + Expect(c.valAt(2), EqualTo("b")); + Expect(c.valAt(3), EqualTo("c")); + } + + [Test] + public void ConsOnIMapEntryReplacesExisting() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + IPersistentMap c = m.cons(new MapEntry(2, "c")); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + + Expect(c.count(), EqualTo(2)); + Expect(c.valAt(1), EqualTo("a")); + Expect(c.valAt(2), EqualTo("c")); + } + + + [Test] + public void ConsOnDictionaryEntryAddsNew() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + IPersistentMap c = m.cons(new DictionaryEntry(3, "c")); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + + Expect(c.count(), EqualTo(3)); + Expect(c.valAt(1), EqualTo("a")); + Expect(c.valAt(2), EqualTo("b")); + Expect(c.valAt(3), EqualTo("c")); + } + + [Test] + public void ConsOnDictionaryEntryReplacesExisting() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + IPersistentMap c = m.cons(new DictionaryEntry(2, "c")); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + + Expect(c.count(), EqualTo(2)); + Expect(c.valAt(1), EqualTo("a")); + Expect(c.valAt(2), EqualTo("c")); + } + + [Test] + public void ConsOnKeyValuePairAddsNew() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + IPersistentMap c = m.cons(new KeyValuePair(3, "c")); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + + Expect(c.count(), EqualTo(3)); + Expect(c.valAt(1), EqualTo("a")); + Expect(c.valAt(2), EqualTo("b")); + Expect(c.valAt(3), EqualTo("c")); + } + + [Test] + public void ConsOnKeyValuePairReplacesExisting() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + IPersistentMap c = m.cons(new KeyValuePair(2, "c")); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + + Expect(c.count(), EqualTo(2)); + Expect(c.valAt(1), EqualTo("a")); + Expect(c.valAt(2), EqualTo("c")); + } + + [Test] + public void ConsOnIPVAddsNew() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + IPersistentVector v = PersistentVector.create(3, "c"); + IPersistentMap c = m.cons(v); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + + Expect(c.count(), EqualTo(3)); + Expect(c.valAt(1), EqualTo("a")); + Expect(c.valAt(2), EqualTo("b")); + Expect(c.valAt(3), EqualTo("c")); + } + + [Test] + public void ConsOnIPVReplacesExisting() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + IPersistentVector v = PersistentVector.create(2, "c"); + IPersistentMap c = m.cons(v); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + + Expect(c.count(), EqualTo(2)); + Expect(c.valAt(1), EqualTo("a")); + Expect(c.valAt(2), EqualTo("c")); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ConsOnNon2IPVFails() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentArrayMap.create(d); + + IPersistentVector v = PersistentVector.create(2, "c", 3, "d"); + IPersistentMap c = m.cons(v); + + } + + [Test] + public void ConsOnIPersistentMapAddsOrReplacesMany() + { + Dictionary d1 = new Dictionary(); + d1[1] = "a"; + d1[2] = "b"; + + IPersistentMap m1 = PersistentArrayMap.create(d1); + + + Dictionary d2 = new Dictionary(); + d2[2] = "c"; + d2[3] = "d"; + + IPersistentMap m2 = PersistentArrayMap.create(d2); + IPersistentMap m3 = m1.cons(m2); + + + Expect(m1.count(), EqualTo(2)); + Expect(m1.valAt(1), EqualTo("a")); + Expect(m1.valAt(2), EqualTo("b")); + + Expect(m2.count(), EqualTo(2)); + Expect(m2.valAt(2), EqualTo("c")); + Expect(m2.valAt(3), EqualTo("d")); + + Expect(m3.count(), EqualTo(3)); + Expect(m3.valAt(1), EqualTo("a")); + Expect(m3.valAt(2), EqualTo("c")); + Expect(m3.valAt(3), EqualTo("d")); + } + + [Test] + public void InvokeOn1ArgDoesValAt1() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IFn f = (IFn)PersistentArrayMap.create(d); + + Expect(f.invoke(1), EqualTo("a")); + Expect(f.invoke(7),Null); + + } + [Test] + public void InvokeOn2ArgsDoesValAt2() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IFn f = (IFn)PersistentArrayMap.create(d); + + Expect(f.invoke(1,99), EqualTo("a")); + Expect(f.invoke(7,99), EqualTo(99)); + } + + [Test] + [ExpectedException(typeof(NotImplementedException))] + public void IDictionary_Add_fails() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + id.Add(1, "c"); + } + + [Test] + [ExpectedException(typeof(NotImplementedException))] + public void IDictionary_Clear_fails() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + id.Clear(); + } + + [Test] + [ExpectedException(typeof(NotImplementedException))] + public void IDictionary_Remove_fails() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + id.Remove(1); + } + + [Test] + public void IDictionary_Contains_finds_existing_key() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + Expect(id.Contains(1)); + } + + + + [Test] + public void IDictionary_Contains_does_not_find_existing_key() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + + Expect(id.Contains(3),False); + } + + [Test] + public void IDictionary_IsFixedSize_is_true() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + + Expect(id.IsFixedSize); + } + + [Test] + public void IDictionary_IsReadOnly_is_true() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + + Expect(id.IsReadOnly); + } + + [Test] + public void IDictionary_index_acts_like_valAt() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + Expect(id[2], EqualTo("b")); + Expect(id[3], Null); + } + + [Test] + public void IDictionary_Keys_creates_key_collection() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + ICollection keys = id.Keys; + + Expect(keys.Count, EqualTo(2)); + int[] akeys = new int[2]; + keys.CopyTo(akeys, 0); + Array.Sort(akeys); + Expect(akeys[0], EqualTo(1)); + Expect(akeys[1], EqualTo(2)); + } + + [Test] + public void IDictionary_Values_creates_value_collection() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + ICollection vals = id.Values; + + Expect(vals.Count, EqualTo(2)); + string[] avals = new string[2]; + vals.CopyTo(avals, 0); + Array.Sort(avals); + Expect(avals[0], EqualTo("a")); + Expect(avals[1], EqualTo("b")); + } + + + + + [Test] + public void IDictionary_GetEnumerator_returns_an_enumerator() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IDictionary id = (IDictionary)PersistentArrayMap.create(d); + IDictionaryEnumerator e = id.GetEnumerator(); + + Expect(e.MoveNext()); + DictionaryEntry de1 = (DictionaryEntry)e.Current; + Expect(e.MoveNext()); + DictionaryEntry de2 = (DictionaryEntry)e.Current; + Expect(e.MoveNext(), False); + + Expect(de1.Key, EqualTo(1) | EqualTo(2)); + Expect(de2.Key, EqualTo(1) | EqualTo(2)); + Expect(de1.Value, EqualTo(((int)de1.Key) == 1 ? "a" : "b")); + Expect(de2.Value, EqualTo(((int)de2.Key) == 1 ? "a" : "b")); + } + + [Test] + public void ICollection_CopyTo_Copies() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + ICollection c = (ICollection)PersistentArrayMap.create(d); + IMapEntry[] a = new IMapEntry[c.Count]; + c.CopyTo(a, 0); + + int key0 = (int)a[0].key(); + int key1 = (int)a[1].key(); + string val0 = (string)a[0].val(); + string val1 = (string)a[1].val(); + + Expect(key0, EqualTo(1) | EqualTo(2)); + Expect(key1, EqualTo(key0 == 1 ? 2 : 1)); + Expect(val0, EqualTo(key0 == 1 ? "a" : "b")); + Expect(val1, EqualTo(key1 == 1 ? "a" : "b")); + } + + + [Test] + public void ICollection_Count_returns_count_of_items() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + ICollection c = (ICollection)PersistentArrayMap.create(d); + + Expect(c.Count, EqualTo(2)); + } + + [Test] + public void ICollection_IsSynchronized_is_true() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + ICollection c = (ICollection)PersistentArrayMap.create(d); + + Expect(c.IsSynchronized); + } + + + [Test] + [ExpectedException(typeof(NotImplementedException))] + public void ICollection_SyncRoot_fails() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + ICollection c = (ICollection)PersistentArrayMap.create(d); + + object s = c.SyncRoot; + } + + + #endregion + } + + [TestFixture] + public class PersistentArrayMap_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + Dictionary d = new Dictionary(); + d[1] = "abc"; + + _objWithNullMeta = (IObj)PersistentArrayMap.create(d); + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(PersistentArrayMap); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + } + +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentHashMapTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentHashMapTests.cs new file mode 100644 index 00000000..200494b5 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentHashMapTests.cs @@ -0,0 +1,242 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; +using System.Collections; + + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class PersistentHashMapTests : AssertionHelper + { + + #region C-tor tests + + [Test] + public void CreateOnEmptyDictionaryReturnsEmptyMap() + { + Dictionary d = new Dictionary(); + IPersistentMap m = PersistentHashMap.create(d); + + Expect(m.count(), EqualTo(0)); + } + + [Test] + public void CreateOnDictionaryReturnsMap() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentHashMap.create(d); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + Expect(m.containsKey(3), False); + } + + [Test] + public void CreateOnEmptyListReturnsEmptyMap() + { + ArrayList a = new ArrayList(); + IPersistentMap m = PersistentHashMap.create(a); + + Expect(m.count(), EqualTo(0)); + } + + [Test] + public void CreateOnListReturnsMap() + { + object[] items = new object[] { 1, "a", 2, "b" }; + ArrayList a = new ArrayList(items); + + IPersistentMap m = PersistentHashMap.create(a); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + Expect(m.containsKey(3), False); + } + + [Test] + public void CreateOnEmptyISeqReturnsEmptyMap() + { + object[] items = new object[] {}; + ArrayList a = new ArrayList(items); + ISeq s = PersistentList.create(a).seq(); + IPersistentMap m = PersistentHashMap.create(s); + + Expect(m.count(), EqualTo(0)); + } + + [Test] + public void CreateOnISeqReturnsMap() + { + object[] items = new object[] { 1, "a", 2, "b" }; + ArrayList a = new ArrayList(items); + ISeq s = PersistentList.create(a).seq(); + IPersistentMap m = PersistentHashMap.create(s); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + Expect(m.containsKey(3), False); + } + + [Test] + public void CreateOnNoArgsReturnsEmptyMap() + { + PersistentHashMap m = PersistentHashMap.create(); + + Expect(m.count(), EqualTo(0)); + Expect(m.meta(), Null); + } + + [Test] + public void CreateOnNoArgsReturnsMap() + { + PersistentHashMap m = PersistentHashMap.create(1, "a", 2, "b"); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + Expect(m.containsKey(3), False); + Expect(m.meta(), Null); + } + + + [Test] + public void CreateOnMetaNoArgsReturnsEmptyMap() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + PersistentHashMap m = PersistentHashMap.create(meta); + + Expect(m.count(), EqualTo(0)); + Expect(m.meta(), SameAs(meta)); + mocks.VerifyAll(); + } + + [Test] + public void CreateOnMetaNoArgsReturnsMap() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + PersistentHashMap m = PersistentHashMap.create(meta,1, "a", 2, "b"); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + Expect(m.containsKey(3), False); + Expect(m.meta(), SameAs(meta)); + mocks.VerifyAll(); + } + + #endregion + + #region Associative tests + + #endregion + + #region IPersistentMap tests + + #endregion + + #region IPersistentCollection tests + + #endregion + + #region Big tests + + [Test] + public void DoSomeBigTests() + { + DoBigTest(100); + DoBigTest(1000); + DoBigTest(10000); + DoBigTest(100000); + } + + public void DoBigTest(int numEntries) + { + System.Console.WriteLine("Testing {0} items.", numEntries); + + Random rnd = new Random(); + Dictionary dict = new Dictionary(numEntries); + for (int i = 0; i < numEntries; i++) + { + int r = rnd.Next(); + dict[r] = r; + } + PersistentHashMap m = (PersistentHashMap) PersistentHashMap.create(dict); + + Expect(m.count(),EqualTo(dict.Count)); + + foreach ( int key in dict.Keys ) + { + Expect(m.containsKey(key)); + Expect(m.valAt(key),EqualTo(key)); + } + + for ( ISeq s = m.seq(); s != null; s = s.rest() ) + Expect(dict.ContainsKey((int)((IMapEntry)s.first()).key())); + + } + + #endregion + + } + + [TestFixture] + public class PersistentHashMap_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + PersistentHashMap m = PersistentHashMap.create(1, "a", 2, "b"); + + + _objWithNullMeta = (IObj)m; + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(PersistentHashMap); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + } + +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentHashSetTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentHashSetTests.cs new file mode 100644 index 00000000..9e71e14d --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentHashSetTests.cs @@ -0,0 +1,188 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; +using System.Collections; + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class PersistentHashSetTests : AssertionHelper + { + + #region C-tor tests + + [Test] + public void CreateOnEmptyListReturnsEmptySet() + { + ArrayList a = new ArrayList(); + IPersistentSet m = PersistentHashSet.create1(a); + + Expect(m.count(), EqualTo(0)); + } + + [Test] + public void CreateOnListReturnsSet() + { + object[] items = new object[] { 1, "a" }; + ArrayList a = new ArrayList(items); + + IPersistentSet m = PersistentHashSet.create1(a); + + Expect(m.count(), EqualTo(2)); + Expect(m.contains(1)); + Expect(m.contains("a")); + Expect(m.contains(3), False); + } + + [Test] + public void CreateOnEmptyISeqReturnsEmptySet() + { + object[] items = new object[] { }; + ArrayList a = new ArrayList(items); + ISeq s = PersistentList.create(a).seq(); + IPersistentSet m = PersistentHashSet.create(s); + + Expect(m.count(), EqualTo(0)); + } + + [Test] + public void CreateOnISeqReturnsSet() + { + object[] items = new object[] { 1, "a" }; + ArrayList a = new ArrayList(items); + ISeq s = PersistentList.create(a).seq(); + IPersistentSet m = PersistentHashSet.create(s); + + Expect(m.count(), EqualTo(2)); + Expect(m.contains(1)); + Expect(m.contains("a")); + Expect(m.contains(3), False); + } + + [Test] + public void CreateOnNoArgsReturnsEmptySet() + { + PersistentHashSet m = PersistentHashSet.create(); + + Expect(m.count(), EqualTo(0)); + Expect(m.meta(), Null); + } + + [Test] + public void CreateOnNoArgsReturnsSet() + { + PersistentHashSet m = PersistentHashSet.create(1, "a"); + + Expect(m.count(), EqualTo(2)); + Expect(m.contains(1)); + Expect(m.contains("a")); + Expect(m.contains(3), False); + Expect(m.meta(), Null); + } + + + + #endregion + + #region Associative tests + + #endregion + + #region IPersistentMap tests + + #endregion + + #region IPersistentCollection tests + + #endregion + + #region Big tests + + [Test] + public void DoSomeBigTests() + { + DoBigTest(100); + DoBigTest(1000); + DoBigTest(10000); + DoBigTest(100000); + } + + public void DoBigTest(int numEntries) + { + System.Console.WriteLine("Testing {0} items.", numEntries); + + Random rnd = new Random(); + Dictionary dict = new Dictionary(numEntries); + for (int i = 0; i < numEntries; i++) + { + int r = rnd.Next(); + dict[r] = r; + } + + object[] items = dict.Keys.ToArray(); + + PersistentHashSet m = (PersistentHashSet)PersistentHashSet.create(items); + + Expect(m.count(), EqualTo(dict.Count)); + + foreach (int key in dict.Keys) + { + Expect(m.contains(key)); + } + + for (ISeq s = m.seq(); s != null; s = s.rest()) + Expect(dict.ContainsKey((int)s.first())); + + } + + #endregion + } + + [TestFixture] + public class PersistentHashSet_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + PersistentHashSet m = PersistentHashSet.create(1, "a", 2, "b"); + + + _objWithNullMeta = (IObj)m; + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(PersistentHashSet); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + } + +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentListTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentListTests.cs new file mode 100644 index 00000000..dd4539d4 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentListTests.cs @@ -0,0 +1,245 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class PersistentListTests : AssertionHelper + { + #region C-tor tests + + [Test] + public void OneArgCtorConstructsListOfOneElement() + { + PersistentList p = new PersistentList("abc"); + + Expect(p.first(), EqualTo("abc")); + Expect(p.rest(), Null); + Expect(p.count(), EqualTo(1)); + } + + [Test] + public void ListCtorConstructsListOfSeveralElements() + { + object[] items = new object[] { 1, "abc", 2, "def" }; + IPersistentList p = PersistentList.create(items); + + Expect(p.count(), EqualTo(4)); + + ISeq s = p.seq(); + Expect(s.first(), EqualTo(1)); + Expect(s.rest().first(), EqualTo("abc")); + Expect(s.rest().rest().first(), EqualTo(2)); + Expect(s.rest().rest().rest().first(), EqualTo("def")); + Expect(s.rest().rest().rest().rest(), Null); + } + + + #endregion + + #region IPersistentStack tests + + [Test] + public void PeekYieldsFirstElementAndListUnchanged() + { + PersistentList p = (PersistentList)PersistentList.create(new object[] { "abc", 1, "def" }); + + Expect(p.peek(), EqualTo("abc")); + Expect(p.count(), EqualTo(3)); + } + + [Test] + public void PopLosesfirstElement() + { + PersistentList p = (PersistentList)PersistentList.create(new object[]{"abc", 1, "def"}); + PersistentList p2 = (PersistentList)p.pop(); + Expect(p2.count(), EqualTo(2)); + Expect(p2.peek(), EqualTo(1)); + } + + [Test] + public void PopOnSingletonListYieldsEmptyList() + { + PersistentList p = new PersistentList("abc"); + IPersistentStack s = p.pop(); + Expect(s.count(), EqualTo(0)); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void DoublePopOnSingletonListYieldsException() + { + PersistentList p = new PersistentList("abc"); + IPersistentStack s = p.pop().pop(); + } + + #endregion + + #region IPersistentCollection tests + + [Test] + public void EmptyHasNoElements() + { + PersistentList p = new PersistentList("abc"); + IPersistentCollection c = p.empty(); + + Expect(c.count(), EqualTo(0)); + } + + [Test] + public void EmptyPreservesMeta() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + IPersistentCollection p = (IPersistentCollection)new PersistentList("abc").withMeta(meta); + IObj obj = (IObj) p.empty(); + + Expect(obj.meta(), SameAs(meta)); + mocks.VerifyAll(); + } + + #endregion + + #region IReduce tests + + [Test] + public void ReduceWithNoStartIterates() + { + MockRepository mocks = new MockRepository(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke(1, 2)).Return(5); + RMExpect.Call(fn.invoke(5, 3)).Return(7); + mocks.ReplayAll(); + + PersistentList p = (PersistentList)PersistentList.create(new object[] { 1, 2, 3 }); + object ret = p.reduce(fn); + + Expect(ret, EqualTo(7)); + + mocks.VerifyAll(); + } + + [Test] + public void ReduceWithStartIterates() + { + MockRepository mocks = new MockRepository(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke(20, 1)).Return(10); + RMExpect.Call(fn.invoke(10, 2)).Return(5); + RMExpect.Call(fn.invoke(5, 3)).Return(7); + mocks.ReplayAll(); + + PersistentList p = (PersistentList)PersistentList.create(new object[] { 1, 2, 3 }); + object ret = p.reduce(fn, 20); + + Expect(ret, EqualTo(7)); + + mocks.VerifyAll(); + } + + + #endregion + + } + + [TestFixture] + public class PersistentList_ISeq_Tests : ISeqTestHelper + { + PersistentList _pl; + PersistentList _plWithMeta; + object[] _values; + + + [SetUp] + public void Setup() + { + PersistentList p1 = new PersistentList("abc"); + PersistentList p2 = (PersistentList)p1.cons("def"); + _pl = (PersistentList)p2.cons(7); + _values = new object[] { 7, "def", "abc" }; + _plWithMeta = (PersistentList)_pl.withMeta(PersistentHashMap.create("a", 1)); + } + + [Test] + public void ISeq_has_correct_valuess() + { + VerifyISeqContents(_pl, _values); + } + + [Test] + public void ISeq_with_meta_has_correct_valuess() + { + VerifyISeqContents(_plWithMeta, _values); + } + + [Test] + public void Rest_has_correct_type() + { + VerifyISeqRestTypes(_pl, typeof(PersistentList)); + } + + [Test] + public void Cons_works() + { + VerifyISeqCons(_pl, "pqr", _values); + } + + [Test] + public void ConsPreservesMeta() + { + PersistentList p2 = (PersistentList)_plWithMeta.cons("def"); + Expect(p2.meta(), SameAs(_plWithMeta.meta())); + } + } + + + [TestFixture] + public class PersistentList_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + PersistentList p1 = (PersistentList)PersistentList.create(new object[] { "abc", "def" }); + + + _objWithNullMeta = (IObj)p1; + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(PersistentList); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentQueueTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentQueueTests.cs new file mode 100644 index 00000000..3281ac44 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentQueueTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add tests for PersistentQueue + class PersistentQueueTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentStructMapTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentStructMapTests.cs new file mode 100644 index 00000000..c2db638a --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentStructMapTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add tests for PersistentStructMap + class PersistentStructMapTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentTreeMapTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentTreeMapTests.cs new file mode 100644 index 00000000..aebfd478 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentTreeMapTests.cs @@ -0,0 +1,233 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; +using System.Collections; + + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class PersistentTreeMapTests : AssertionHelper + { + #region C-tor tests + + [Test] + public void CreateOnEmptyDictionaryReturnsEmptyMap() + { + Dictionary d = new Dictionary(); + IPersistentMap m = PersistentTreeMap.create(d); + + Expect(m.count(), EqualTo(0)); + } + + [Test] + public void CreateOnDictionaryReturnsMap() + { + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + IPersistentMap m = PersistentTreeMap.create(d); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + Expect(m.containsKey(3), False); + } + + //[Test] + //public void CreateOnEmptyListReturnsEmptyMap() + //{ + // ArrayList a = new ArrayList(); + // IPersistentMap m = PersistentTreeMap.create(a); + + // Expect(m.count(), EqualTo(0)); + //} + + //[Test] + //public void CreateOnListReturnsMap() + //{ + // object[] items = new object[] { 1, "a", 2, "b" }; + // ArrayList a = new ArrayList(items); + + // IPersistentMap m = PersistentTreeMap.create(a); + + // Expect(m.count(), EqualTo(2)); + // Expect(m.valAt(1), EqualTo("a")); + // Expect(m.valAt(2), EqualTo("b")); + // Expect(m.containsKey(3), False); + //} + + [Test] + public void CreateOnEmptyISeqReturnsEmptyMap() + { + object[] items = new object[] { }; + ArrayList a = new ArrayList(items); + ISeq s = PersistentList.create(a).seq(); + IPersistentMap m = PersistentTreeMap.create(s); + + Expect(m.count(), EqualTo(0)); + } + + [Test] + public void CreateOnISeqReturnsMap() + { + object[] items = new object[] { 1, "a", 2, "b" }; + ArrayList a = new ArrayList(items); + ISeq s = PersistentList.create(a).seq(); + IPersistentMap m = PersistentTreeMap.create(s); + + Expect(m.count(), EqualTo(2)); + Expect(m.valAt(1), EqualTo("a")); + Expect(m.valAt(2), EqualTo("b")); + Expect(m.containsKey(3), False); + } + + [Test] + public void DefaultCtorReturnsEmptyMap() + { + PersistentTreeMap m = new PersistentTreeMap(); + + Expect(m.count(), EqualTo(0)); + Expect(m.meta(), Null); + } + + + //[Test] + //public void CreateOnMetaNoArgsReturnsEmptyMap() + //{ + // MockRepository mocks = new MockRepository(); + // IPersistentMap meta = mocks.StrictMock(); + // mocks.ReplayAll(); + + // PersistentTreeMap m = PersistentTreeMap.create(meta); + + // Expect(m.count(), EqualTo(0)); + // Expect(m.meta(), SameAs(meta)); + // mocks.VerifyAll(); + //} + + //[Test] + //public void CreateOnMetaNoArgsReturnsMap() + //{ + // MockRepository mocks = new MockRepository(); + // IPersistentMap meta = mocks.StrictMock(); + // mocks.ReplayAll(); + + // PersistentTreeMap m = PersistentTreeMap.create(meta, 1, "a", 2, "b"); + + // Expect(m.count(), EqualTo(2)); + // Expect(m.valAt(1), EqualTo("a")); + // Expect(m.valAt(2), EqualTo("b")); + // Expect(m.containsKey(3), False); + // Expect(m.meta(), SameAs(meta)); + // mocks.VerifyAll(); + //} + + #endregion + + #region Associative tests + + #endregion + + #region IPersistentMap tests + + #endregion + + #region IPersistentCollection tests + + #endregion + + #region Big tests + + [Test] + public void DoSomeBigTests() + { + DoBigTest(100); + DoBigTest(1000); + DoBigTest(10000); + DoBigTest(100000); + } + + public void DoBigTest(int numEntries) + { + System.Console.WriteLine("Testing {0} items.", numEntries); + + Random rnd = new Random(); + Dictionary dict = new Dictionary(numEntries); + for (int i = 0; i < numEntries; i++) + { + int r = rnd.Next(); + dict[r] = r; + } + PersistentTreeMap m = (PersistentTreeMap)PersistentTreeMap.create(dict); + + Expect(m.count(), EqualTo(dict.Count)); + + foreach (int key in dict.Keys) + { + Expect(m.containsKey(key)); + Expect(m.valAt(key), EqualTo(key)); + } + + for (ISeq s = m.seq(); s != null; s = s.rest()) + Expect(dict.ContainsKey((int)((IMapEntry)s.first()).key())); + + } + + #endregion + } + + + [TestFixture] + public class PersistentTreeMap_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + Dictionary d = new Dictionary(); + d[1] = "a"; + d[2] = "b"; + + PersistentTreeMap m = (PersistentTreeMap)PersistentTreeMap.create(d); + + + _objWithNullMeta = (IObj)m; + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(PersistentTreeMap); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + } + +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentTreeSetTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentTreeSetTests.cs new file mode 100644 index 00000000..77b9a4d4 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentTreeSetTests.cs @@ -0,0 +1,58 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add tests for PersistentTreeSet + class PersistentTreeSetTests + { + } + + [TestFixture] + public class PersistentTreeSet_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + PersistentTreeSet m = PersistentTreeSet.create("a", "b"); + + + _objWithNullMeta = (IObj)m; + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(PersistentTreeSet); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + } + +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentVectorTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentVectorTests.cs new file mode 100644 index 00000000..bde46e9f --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/PersistentVectorTests.cs @@ -0,0 +1,330 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class PersistentVectorTests : AssertionHelper + { + + #region C-tor tests + + [Test] + public void CreateOnISeqReturnsCorrectCount() + { + Range r = new Range(2,5); + PersistentVector v = PersistentVector.create(r); + + Expect(v.count(),EqualTo(r.count())); + } + + [Test] + public void CreateOnISeqHasItems() + { + Range r = new Range(2, 5); + PersistentVector v = PersistentVector.create(r); + + Expect(v.nth(0), EqualTo(2)); + Expect(v.nth(1), EqualTo(3)); + Expect(v.nth(2), EqualTo(4)); + } + + [Test] + public void CreateOnISeqWithManyItemsWorks() + { + // Want to bust out of the first tail, so need to insert more than 32 elements. + Range r = new Range(2, 1000); + PersistentVector v = PersistentVector.create(r); + + Expect(v.count(), EqualTo(r.count())); + for (int i = 0; i < v.count(); ++i) + Expect(v.nth(i), EqualTo(i + 2)); + } + + [Test] + public void CreateOnISeqWithManyManyItemsWorks() + { + // Want to bust out of the first tail, so need to insert more than 32 elements. + // Let's get out of the second level, too. + + Range r = new Range(2, 100000); + PersistentVector v = PersistentVector.create(r); + + Expect(v.count(), EqualTo(r.count())); + for (int i = 0; i < v.count(); ++i) + Expect(v.nth(i), EqualTo(i + 2)); + } + + [Test] + public void CreateOnMultipleItemsWorks() + { + PersistentVector v = PersistentVector.create(2,3,4); + + Expect(v.count(),EqualTo(3)); + Expect(v.nth(0), EqualTo(2)); + Expect(v.nth(1), EqualTo(3)); + Expect(v.nth(2), EqualTo(4)); + } + + #endregion + + #region IPersistentVector tests + + + // nth - tested in c-tor tests + + + [Test] + public void CountYieldsLength() + { + PersistentVector v = PersistentVector.create(1, 2, 3); + + Expect(v.length(), EqualTo(3)); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void NthOutOfRangeLowFails() + { + PersistentVector v = PersistentVector.create(1, 2, 3); + object obj = v.nth(-4); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void NthOutOfRangeHighFails() + { + PersistentVector v = PersistentVector.create(1, 2, 3); + object obj = v.nth(4); + } + + [Test] + public void AssocNReplacesInRangeForSmall() + { + Range r = new Range(2, 5); + PersistentVector v1 = PersistentVector.create(r); + IPersistentVector v2 = v1.assocN(1,10); + + Expect(v1.nth(0), EqualTo(2)); + Expect(v1.nth(1), EqualTo(3)); + Expect(v1.nth(2), EqualTo(4)); + Expect(v1.count(), EqualTo(3)); + Expect(v2.nth(0), EqualTo(2)); + Expect(v2.nth(1), EqualTo(10)); + Expect(v2.nth(2), EqualTo(4)); + Expect(v2.count(), EqualTo(3)); + } + + [Test] + public void AssocNAddsAtEndForSmall() + { + Range r = new Range(2, 5); + PersistentVector v1 = PersistentVector.create(r); + IPersistentVector v2 = v1.assocN(3, 10); + + Expect(v1.nth(0), EqualTo(2)); + Expect(v1.nth(1), EqualTo(3)); + Expect(v1.nth(2), EqualTo(4)); + Expect(v1.count(), EqualTo(3)); + Expect(v2.nth(0), EqualTo(2)); + Expect(v2.nth(1), EqualTo(3)); + Expect(v2.nth(2), EqualTo(4)); + Expect(v2.nth(3), EqualTo(10)); + Expect(v2.count(), EqualTo(4)); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void AssocNOutOfRangeLowThrowsException() + { + Range r = new Range(2, 5); + PersistentVector v1 = PersistentVector.create(r); + IPersistentVector v2 = v1.assocN(-4, 10); + } + + [Test] + [ExpectedException(typeof(IndexOutOfRangeException))] + public void AssocNOutOfRangeHighThrowsException() + { + Range r = new Range(2, 5); + PersistentVector v1 = PersistentVector.create(r); + IPersistentVector v2 = v1.assocN(4, 10); + } + + [Test] + public void AssocNAddsAtEndForEmpty() + { + PersistentVector v1 = PersistentVector.create(); + IPersistentVector v2 = v1.assocN(0, "abc"); + + Expect(v1.count(), EqualTo(0)); + Expect(v2.count(), EqualTo(1)); + Expect(v2.nth(0), EqualTo("abc")); + } + + [Test] + public void AssocNChangesForBig() + { + Range r = new Range(2, 100000); + PersistentVector v1 = PersistentVector.create(r); + IPersistentVector v2 = v1; + + for (int i = 0; i < 110000; i++) + v2 = v2.assocN(i, i + 20); + + for ( int i=0; i(); + mocks.ReplayAll(); + + PersistentVector v1 = PersistentVector.create(1, 2, 3); + IPersistentCollection e1 = v1.empty(); + + PersistentVector v2 = (PersistentVector) v1.withMeta(meta); + IPersistentCollection e2 = v2.empty(); + + Expect(((IObj)e1).meta(), Null); + Expect(((IObj)e2).meta(), SameAs(meta)); + + mocks.VerifyAll(); + } + + + #endregion + + #region IPersistentStack tests + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void PopOnEmptyThrowsException() + { + PersistentVector v = PersistentVector.create(); + IPersistentStack s = v.pop(); + } + + [Test] + public void PopOnSizeOneReturnsEmpty() + { + PersistentVector v = PersistentVector.create(1); + IPersistentStack s = v.pop(); + + Expect(s.count(), EqualTo(0)); + } + + [Test] + public void PopOnSmallReturnsOneLess() + { + Range r = new Range(2, 20); + PersistentVector v = PersistentVector.create(r); + IPersistentStack s = v.pop(); + + Expect(v.count(),EqualTo(r.count())); + Expect(s.count(),EqualTo(v.count()-1)); + } + + [Test] + public void PopOnBigWorks() + { + Range r = new Range(0, 100000); + PersistentVector v = PersistentVector.create(r); + IPersistentStack s = v; + for (int i = 16; i < 100000; i++) + s = s.pop(); + + Expect(v.count(), EqualTo(r.count())); + Expect(s.count(), EqualTo(16)); + } + + + #endregion + + #region IFn tests + + #endregion + } + + [TestFixture] + public class PersistentVector_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + PersistentVector v = PersistentVector.create(2, 3, 4); + + _objWithNullMeta = (IObj)v; + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(PersistentVector); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + } + +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/RangeTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/RangeTests.cs new file mode 100644 index 00000000..7948a681 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/RangeTests.cs @@ -0,0 +1,182 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class RangeTests : AssertionHelper + { + #region C-tor tests + + [Test] + public void Basic_ctor_has_no_meta() + { + Range r = new Range(2, 5); + Expect(r.meta(), Null); + } + + [Test] + public void Meta_ctor_has_meta() + { + MockRepository mocks = new MockRepository(); + IPersistentMap meta = mocks.StrictMock(); + mocks.ReplayAll(); + + Range r = new Range(meta, 2, 5); + + Expect(r.meta(), EqualTo(meta)); + + mocks.VerifyAll(); + } + + #endregion + + #region IPersistentCollection tests + + [Test] + public void Range_has_correct_count() + { + Range r = new Range(2, 20); + + Expect(r.count(), EqualTo(18)); + } + + + #endregion + + #region IReduce tests + + [Test] + public void ReduceWithNoStartIterates() + { + MockRepository mocks = new MockRepository(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke(2, 3)).Return(5); + RMExpect.Call(fn.invoke(5, 4)).Return(7); + mocks.ReplayAll(); + + Range r = new Range(2, 5); + object ret = r.reduce(fn); + + Expect(ret, EqualTo(7)); + + mocks.VerifyAll(); + } + + [Test] + public void ReduceWithStartIterates() + { + MockRepository mocks = new MockRepository(); + IFn fn = mocks.StrictMock(); + RMExpect.Call(fn.invoke(20, 2)).Return(10); + RMExpect.Call(fn.invoke(10, 3)).Return(5); + RMExpect.Call(fn.invoke(5, 4)).Return(7); + mocks.ReplayAll(); + + Range r = new Range(2, 5); + object ret = r.reduce(fn, 20); + + Expect(ret, EqualTo(7)); + + mocks.VerifyAll(); + } + + #endregion + + // TODO: test stream capability of Range + } + + [TestFixture] + public class Range_ISeq_Tests : ISeqTestHelper + { + Range _r; + Range _rWithMeta; + object[] _values; + + [SetUp] + public void Setup() + { + IPersistentMap meta = PersistentHashMap.create("a", 1, "b", 2); + + _r = new Range(2, 5); + _rWithMeta = new Range(meta, 2, 5); + _values = new object[] { 2, 3, 4 }; + } + + [Test] + public void Range_has_correct_values() + { + VerifyISeqContents(_r, _values); + } + + [Test] + public void Range_with_meta_has_correct_values() + { + VerifyISeqContents(_rWithMeta, _values); + } + + [Test] + public void Rest_preserves_meta() + { + VerifyISeqRestMaintainsMeta(_rWithMeta); + } + + [Test] + public void Rest_preserves_type() + { + VerifyISeqRestTypes(_r, typeof(Range)); + } + + [Test] + public void Cons_works() + { + VerifyISeqCons(_r, 12, _values); + } + } + + [TestFixture] + public class Range_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + Range r = new Range(2, 5); + + _objWithNullMeta = (IObj)r; + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(Range); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/RefTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/RefTests.cs new file mode 100644 index 00000000..efc67335 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/RefTests.cs @@ -0,0 +1,23 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add tests for Ref + + class RefTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/RestFnImplTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/RestFnImplTests.cs new file mode 100644 index 00000000..3d9870e4 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/RestFnImplTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + //TODO: Add RestFnImpl tests + class RestFnImplTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/RestFnTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/RestFnTests.cs new file mode 100644 index 00000000..90ef2168 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/RestFnTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: Add RestFn tests + class RestFnTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/StreamSeqTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/StreamSeqTests.cs new file mode 100644 index 00000000..7f4c4f61 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/StreamSeqTests.cs @@ -0,0 +1,22 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Clojure.Tests.LibTests +{ + // TODO: add tests for StreamSeq + class StreamSeqTests + { + } +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/StringSeqTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/StringSeqTests.cs new file mode 100644 index 00000000..b17280b2 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/StringSeqTests.cs @@ -0,0 +1,163 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; + + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class StringSeqTests : AssertionHelper + { + + #region C-tor tests + + [Test] + public void Create_on_empty_string_yields_null() + { + StringSeq s = StringSeq.create(String.Empty); + + Expect(s, Null); + } + + [Test] + public void Create_on_nonempty_string_yields_a_StringSeq() + { + StringSeq s = StringSeq.create("abcde"); + + Expect(s, Not.Null); + } + + #endregion + + #region IPersistentCollection tests + + [Test] + public void Count_is_string_length() + { + StringSeq s = StringSeq.create("abcde"); + + Expect(s.count(),EqualTo(5)); + } + + #endregion + + #region IndexedSeq tests + + [Test] + public void Initial_index_is_zero() + { + StringSeq s = StringSeq.create("abc"); + + Expect(s.index(), EqualTo(0)); + } + + [Test] + public void Index_of_rest_is_one() + { + StringSeq s = StringSeq.create("abc"); + IndexedSeq i = (IndexedSeq)s.rest(); + + Expect(i.index(), EqualTo(1)); + } + + #endregion + + } + + [TestFixture] + public class StringSeq_ISeq_Tests : ISeqTestHelper + { + StringSeq _s; + StringSeq _sWithMeta; + object[] _values; + + [SetUp] + public void Setup() + { + IPersistentMap meta = PersistentHashMap.create("a", 1, "b", 2); + + _s = StringSeq.create("abcde"); + _sWithMeta = (StringSeq)((IObj)StringSeq.create("abcde")).withMeta(meta); + _values = new object[] { 'a', 'b', 'c', 'd', 'e' }; + } + + [Test] + public void StringSeq_has_correct_ISeq_values() + { + VerifyISeqContents(_s, _values); + } + + [Test] + public void StringSeq_with_meta_has_correct_ISeq_values() + { + VerifyISeqContents(_sWithMeta, _values); + } + + [Test] + public void StringSeq_ISeq_rest_preserves_meta() + { + VerifyISeqRestMaintainsMeta(_sWithMeta); + } + + [Test] + public void StringSeq_ISeq_rest_preserves_type() + { + VerifyISeqRestTypes(_s,typeof(StringSeq)); + } + + [Test] + public void StringSeq_ISeq_cons_works() + { + VerifyISeqCons(_s, 12, _values); + } + + } + + [TestFixture] + public class StringSeq_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + StringSeq s = StringSeq.create("abcde"); + + + _objWithNullMeta = (IObj)s; + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(StringSeq); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + } + +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/SymbolTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/SymbolTests.cs new file mode 100644 index 00000000..3cc32821 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/SymbolTests.cs @@ -0,0 +1,326 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using Rhino.Mocks; + +using clojure.lang; + +using RMExpect = Rhino.Mocks.Expect; +using System.Collections; + + + +namespace Clojure.Tests.LibTests +{ + [TestFixture] + public class SymbolTests : AssertionHelper + { + + #region c-tor tests + + [Test] + public void Intern2CreatesSymbolWithNoNS() + { + Symbol sym = Symbol.intern(null, "abc"); + + Expect(sym.Name, EqualTo("abc")); + Expect(sym.Namespace, Null); + Expect(sym.meta(), Null); + } + + [Test] + public void Intern2CreatesSymbolWithNS() + { + Symbol sym = Symbol.intern("def", "abc"); + + Expect(sym.Name, EqualTo("abc")); + Expect(sym.Namespace, EqualTo("def")); + Expect(sym.meta(), Null); + } + + [Test] + public void Intern2InternsStrings() + { + String symname = new StringBuilder().Append("ab").Append("c").ToString(); + String nsname = new StringBuilder().Append("ab").Append("c").ToString(); + + Symbol sym1 = Symbol.intern(nsname,symname); + Symbol sym2 = Symbol.intern(nsname,symname); + + Expect(String.IsInterned(sym1.Name),Not.Null); + Expect(String.IsInterned(sym1.Namespace), Not.Null); + Expect(Object.ReferenceEquals(sym1.Name, sym2.Name)); + Expect(Object.ReferenceEquals(sym1.Namespace, sym2.Namespace)); + Expect(object.ReferenceEquals(sym1.Name, symname), False); + } + + + + [Test] + public void Intern1CreatesSymbolWithNoNS() + { + Symbol sym = Symbol.intern("abc"); + + Expect(sym.Name, EqualTo("abc")); + Expect(sym.Namespace, Null); + Expect(sym.meta(), Null); + } + + [Test] + public void Intern1CreatesSymbolWithNS() + { + Symbol sym = Symbol.intern("def/abc"); + + Expect(sym.Name, EqualTo("abc")); + Expect(sym.Namespace, EqualTo("def")); + Expect(sym.meta(), Null); + } + + + [Test] + public void Intern1CreatesSymbolWithNSFromLastSlash() + { + Symbol sym = Symbol.intern("ghi/def/abc"); + + Expect(sym.Name, EqualTo("abc")); + Expect(sym.Namespace, EqualTo("ghi/def")); + Expect(sym.meta(), Null); + } + + [Test] + public void Intern1InternsStrings() + { + String name = new StringBuilder().Append("def/").Append("abc").ToString(); + + Symbol sym1 = Symbol.intern(name); + Symbol sym2 = Symbol.intern(name); + + Expect(String.IsInterned(sym1.Name), Not.Null); + Expect(String.IsInterned(sym1.Namespace), Not.Null); + Expect(Object.ReferenceEquals(sym1.Name, sym2.Name)); + Expect(Object.ReferenceEquals(sym1.Namespace, sym2.Namespace)); + } + + #endregion + + #region Object overrides + + [Test] + public void SymToStringWithNoNSIsJustName() + { + Symbol sym = Symbol.intern("abc"); + Expect(sym.ToString(), EqualTo("abc")); + } + + [Test] + public void SymToStringWithNsConcatenatesNames() + { + Symbol sym = Symbol.intern("def", "abc"); + Expect(sym.ToString(), EqualTo("def/abc")); + } + + [Test] + public void EqualsOnIdentityIsTrue() + { + Symbol sym = Symbol.intern("abc"); + Expect(sym.Equals(sym)); + } + + [Test] + public void EqualsOnNonSymbolIsFalse() + { + Symbol sym = Symbol.intern("abc"); + Expect(sym.Equals("abc"), False); + } + + [Test] + public void EqualsOnDissimilarSymbolIsFalse() + { + Symbol sym1 = Symbol.intern("abc"); + Symbol sym2 = Symbol.intern("ab"); + Symbol sym3 = Symbol.intern("def", "abc"); + Symbol sym4 = Symbol.intern("de","abc"); + + Expect(sym1.Equals(sym2), False); + Expect(sym1.Equals(sym3), False); + Expect(sym3.Equals(sym4), False); + } + + [Test] + public void EqualsOnSimilarSymbolIsTrue() + { + + Symbol sym1 = Symbol.intern("abc"); + Symbol sym2 = Symbol.intern("abc"); + Symbol sym3 = Symbol.intern("def", "abc"); + Symbol sym4 = Symbol.intern("def", "abc"); + + Expect(sym1.Equals(sym2)); + Expect(sym3.Equals(sym4)); + } + + [Test] + public void HashCodeDependsOnNames() + { + Symbol sym1 = Symbol.intern("abc"); + Symbol sym2 = Symbol.intern("abc"); + Symbol sym3 = Symbol.intern("def", "abc"); + Symbol sym4 = Symbol.intern("def", "abc"); + Symbol sym5 = Symbol.intern("ab"); + Symbol sym6 = Symbol.intern("de", "abc"); + + Expect(sym1.GetHashCode(), EqualTo(sym2.GetHashCode())); + Expect(sym3.GetHashCode(), EqualTo(sym4.GetHashCode())); + Expect(sym1.GetHashCode(), Not.EqualTo(sym3.GetHashCode())); + Expect(sym1.GetHashCode(), Not.EqualTo(sym5.GetHashCode())); + Expect(sym3.GetHashCode(), Not.EqualTo(sym6.GetHashCode())); + } + + #endregion + + #region Named tests + + // We've been testing these all along. + + #endregion + + #region IFn tests + + [Test] + public void Invoke2IndexesIntoItsFirstArg() + { + Symbol sym1 = Symbol.intern("abc"); + Symbol sym2 = Symbol.intern("abc"); + Symbol sym3 = Symbol.intern("ab"); + + IDictionary dict = new Hashtable(); + dict[sym1] = 7; + dict["abc"] = 8; + + Expect(sym1.invoke(dict), EqualTo(7)); + Expect(sym2.invoke(dict), EqualTo(7)); + Expect(sym3.invoke(dict), Null); + } + + [Test] + public void Invoke3IndexesIntoItsFirstArg() + { + Symbol sym1 = Symbol.intern("abc"); + Symbol sym2 = Symbol.intern("abc"); + Symbol sym3 = Symbol.intern("ab"); + + IDictionary dict = new Hashtable(); + dict[sym1] = 7; + dict["abc"] = 8; + + Expect(sym1.invoke(dict,20), EqualTo(7)); + Expect(sym2.invoke(dict,20), EqualTo(7)); + Expect(sym3.invoke(dict,20), EqualTo(20)); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void InvokeOnNoArgsFails() + { + Symbol sym1 = Symbol.intern("abc"); + object o = sym1.invoke(); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void InvokeOnTooManyArgsFails() + { + Symbol sym1 = Symbol.intern("abc"); + IDictionary dict = new Hashtable(); + dict[sym1] = 7; + dict["abc"] = 8; + + object o = sym1.invoke(dict,20,null); + } + + #endregion + + #region IComparable tests + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void CompareToNonSymbolFails() + { + Symbol sym1 = Symbol.intern("abc"); + int c = sym1.CompareTo("abc"); + } + + [Test] + public void CompareToEqualSymbolIsZero() + { + Symbol sym1 = Symbol.intern("abc"); + Symbol sym2 = Symbol.intern("abc"); + + Expect(sym1.CompareTo(sym2), EqualTo(0)); + } + + [Test] + public void NullNSIsLessThanNonNullNS() + { + Symbol sym1 = Symbol.intern("abc"); + Symbol sym2 = Symbol.intern("a", "abc"); + + Expect(sym1.CompareTo(sym2), LessThan(0)); + Expect(sym2.CompareTo(sym1), GreaterThan(0)); + } + + [Test] + public void DissimilarNSCompareOnNS() + { + Symbol sym1 = Symbol.intern("a", "abc"); + Symbol sym2 = Symbol.intern("b", "abc"); + + Expect(sym1.CompareTo(sym2), LessThan(0)); + Expect(sym2.CompareTo(sym1), GreaterThan(0)); + } + + #endregion + + } + + [TestFixture] + public class Symbol_IObj_Tests : IObjTests + { + MockRepository _mocks; + + [SetUp] + public void Setup() + { + _mocks = new MockRepository(); + IPersistentMap meta = _mocks.StrictMock(); + _mocks.ReplayAll(); + + Symbol sym1 = Symbol.intern("def", "abc"); + + _objWithNullMeta = (IObj)sym1; + _obj = _objWithNullMeta.withMeta(meta); + _expectedType = typeof(Symbol); + } + + [TearDown] + public void Teardown() + { + _mocks.VerifyAll(); + } + + } + +} diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/TestTest.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/TestTest.cs new file mode 100644 index 00000000..3013a348 --- /dev/null +++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/TestTest.cs @@ -0,0 +1,62 @@ +/** + * Copyright (c) David Miller. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + + +using NUnit.Framework; + + +namespace Clojure.Tests.LibTests +{ + + + //public class BaseTest : AssertionHelper + //{ + // [Test] + // public void Test1() + // { + // Console.WriteLine("T1"); + // } + + // [Test] + // public void Test2() + // { + // Console.WriteLine("T2"); + // } + + //} + + //[TestFixture] + //public class TestTest : BaseTest + //{ + // [Test] + // public void Test3() + // { + // Console.WriteLine("T3"); + // } + //} + + + + //[TestFixture] + //public class TestTest2 : BaseTest + //{ + // [Test] + // public void Test4() + // { + // Console.WriteLine("T4"); + // } + //} +} -- cgit v1.2.3-70-g09d2