using System;
using System.Threading;
using System.Reflection;
//For TypeDescriptors.
//using System.ComponentModel;
using System.Collections.Generic;
using NUnit.Framework;
using MPFramework.AppCore.QualityAssurance;
using MPFramework.AppCore.PlatformUtilities;
using MPFramework.AppCore.Manufacturing.TypeHandling;
namespace MPFramework.AppCore.Manufacturing.SpecializedTypes
{
#region Static Test Data Class
/// <summary>
/// Container for common test data.
/// </summary>
public static class QATester_ReferencedValueType_Testdata
{
#region Class Fields
#endregion // Class Fields
#region Static Constructor
static QATester_ReferencedValueType_Testdata()
{
}
#endregion // Static Constructor
}
#endregion // Static Test Data Class
#region Tests
/// <summary>
/// Level 1 tests for functions in ReferencedValueType.
/// </summary>
[TestFixture]
[Category(QAUtils.TestLevel1Name)]
public class QATester_ReferencedValueType_1
{
#region Class Fields
//////// non-generic RVTs instantiated with Int32s.
// First RVT just wraps an Int32. Value = 0.
ReferencedValueType m_rVT1 = new ReferencedValueType((System.ValueType)(Int32)0);
// Second RVT just wraps an Int32. Value = 0.
ReferencedValueType m_rVT2 = new ReferencedValueType((System.ValueType)(Int32)0);
// Third RVT just wraps an Int32. Value = 1. Set in constructor.
ReferencedValueType m_rVT3 = new ReferencedValueType((System.ValueType)(Int32)1);
//////// non-generic RVT's wrapping a simple struct.
// First RVT just wraps the struct. Value = 0,0. We call the parameterized
// constructor on RVTReferencedSSType. We could handle the Type this way, but we
// choose to handle it as a ReferencedValueType, so we cast it to m_rVTSS1
// at construction time in QATester_ReferencedValueType_1(). There are
// situations in which we might wish to handle such a Type either way.
RVTReferencedSSType m_rVTSS1_temp
= new RVTReferencedSSType(new CSharpSimpleStruct());
ReferencedValueType m_rVTSS1;
// Second RVT just wraps the same simple struct. Value = 0,0. This one is used to
// show how to close an open generic RVT at the point of instantiation.
ReferencedValueType m_rVTSS2 = new ReferencedValueType((System.ValueType)(new CSharpSimpleStruct()));
// Third RVT just wraps the same simple struct. Value = 1,0.
ReferencedValueType m_rVTSS3 = new ReferencedValueType((System.ValueType)(new CSharpSimpleStruct(1, 0)));
// Fourth RVT just wraps the same simple struct. Value = 0,1.
ReferencedValueType m_rVTSS4 = new ReferencedValueType((System.ValueType)(new CSharpSimpleStruct(0, 1)));
//////// Int32 RVT's with a reflection access method.
// First RVT just wraps an Int32. Value = 0.
TestReflectionAccessInt32RVT m_rVTRInt32TRA1 = new TestReflectionAccessInt32RVT();
// Second RVT just wraps an Int32. Value = 0.
TestReflectionAccessInt32RVT m_rVTRInt32TRA2 = new TestReflectionAccessInt32RVT();
// Third RVT just wraps an Int32. Value = 1. Set in QATester_ReferencedValueType_1().
TestReflectionAccessInt32RVT m_rVTRInt32TRA3 = new TestReflectionAccessInt32RVT();
//////// Arbitrary Struct Generic RVT's.
// First RVT doesn't implement equatable. Value = 0,0.
GenericRVTReferencedStructClass m_rVTRST1 = new GenericRVTReferencedStructClass();
// Second one doesn't implement equatable, either. Value = 0,0.
GenericRVTReferencedStructClass m_rVTRST2 = new GenericRVTReferencedStructClass();
//////// The rest (from here down) have to be set in the constructor (not default values).
// Third one doesn't implement equatable, either. Value = 1,1.
GenericRVTReferencedStructClass m_rVTRST3 = new GenericRVTReferencedStructClass();
// Next two implement equatable with different numbers (2,2), (3,3).
GenericRVTEquatableReferencedStructClass m_rVTERST1 = new GenericRVTEquatableReferencedStructClass();
GenericRVTEquatableReferencedStructClass m_rVTERST2 = new GenericRVTEquatableReferencedStructClass();
//////// RVT's instantiated as IValueProp's closed as an Int32 (an Int32RVTVP).
// Usual deal - two the same, one different.
ReferencedValueType<Int32> m_Int32RVTVP1 = new Int32RVTVP(0);
ReferencedValueType<Int32> m_Int32RVTVP2 = new Int32RVTVP(0);
ReferencedValueType<Int32> m_Int32RVTVP3 = new Int32RVTVP(1);
#endregion // Class Fields
/// <summary>
/// Obligatory default NUnit constructor. This one actually does something :-)
/// </summary>
public QATester_ReferencedValueType_1()
{
//// Set up Int32 RVT's
m_rVTRInt32TRA3.Value = 1;
//// Set up the struct RVT's.
// Create temp structs, load them and copy.
CSharpSimpleStruct tempRVTS = new CSharpSimpleStruct();
tempRVTS.FirstInt32 = 1;
tempRVTS.SecondInt32 = 1;
m_rVTRST3.Value = tempRVTS;
RVTEquatableStruct tempRVTES = new RVTEquatableStruct();
tempRVTES.FirstInt32 = 2;
tempRVTES.SecondInt32 = 2;
m_rVTERST1.Value = tempRVTES;
tempRVTES.FirstInt32 = 3;
tempRVTES.SecondInt32 = 3;
m_rVTERST2.Value = tempRVTES;
// For our wrapped struct demo.
m_rVTSS1 = (ReferencedValueType)m_rVTSS1_temp;
}
/// <summary>
/// Placeholder.
/// </summary>
[TestFixtureSetUp]
public void TestFixtureSetup(){ }
/// <summary>
/// Placeholder.
/// </summary>
[TestFixtureTearDown]
public void TestFixtureTearDown(){ }
#region Quantitative Tests
///////////////////////////////////////////////////////////////////////
// This section contains tests that verify numerical accuracy of results
// through NUnit assertions. These tests are generally designed to verify
// that results of manipulations of RVT's turn out the way they are
// supposed to.
///////////////////////////////////////////////////////////////////////
/// <summary>
/// This test checks our equality and swap methods on wrapped ints to
/// see if they give the right answer.
/// </summary>
[Test(Description = "Level 1 series a tests for ReferencedValueType")]
public void QATester_RunTest_ReferencedValueType_a()
{
// For all of the equality tests.
bool areEqual = false;
////////// Check out IsValueSameAs first because we'll use it.
//// generic IsValueSameAs tests for IReferencedValueType<T> closed as Int32 on
//// an RVT instantiated as Int32.
areEqual = ((IReferencedValueType<Int32>)m_rVTRInt32TRA1).IsValueSameAs(m_rVTRInt32TRA3);
Assert.IsFalse(areEqual, "generic IsValueSameAs is broken (are equal)");
areEqual = ((IReferencedValueType<Int32>)m_rVTRInt32TRA1).IsValueSameAs(m_rVTRInt32TRA2);
Assert.IsTrue(areEqual, "generic IsValueSameAs is broken (are not equal)");
//// non-generic IsValueSameAs tests for IReferencedValueType RVT instantiated as Int32.
areEqual = ((IReferencedValueType)m_rVT1).IsValueSameAs(m_rVT3);
Assert.IsFalse(areEqual, "non-generic IsValueSameAs is broken (are equal)");
areEqual = ((IReferencedValueType)m_rVT1).IsValueSameAs(m_rVT2);
Assert.IsTrue(areEqual, "non-generic IsValueSameAs is broken (are not equal)");
//// non-generic IsValueSameAs tests for IReferencedValueType RVT instantiated as SimpleStruct.
areEqual = ((IReferencedValueType)m_rVTSS1).IsValueSameAs(m_rVTSS3);
Assert.IsFalse(areEqual, "non-generic SimpleStruct IsValueSameAs is broken (are equal)");
areEqual = ((IReferencedValueType)m_rVTSS1).IsValueSameAs(m_rVTSS2);
Assert.IsTrue(areEqual, "non-generic SimpleStruct IsValueSameAs is broken (are not equal)");
// This one will compare equal because of SimpleStruct's special treatment
// in RVT.Equals(ValueType, ValueType).
areEqual = ((IReferencedValueType)m_rVTSS1).IsValueSameAs(m_rVTSS4);
Assert.IsTrue(areEqual, "non-generic SimpleStruct IsValueSameAs is broken (are not equal)");
//// generic IsValueSameAs tests for IReferencedValueType<T> closed as Int32 on
//// an RVT instantiated as Int32RVTVP.
areEqual = ((IReferencedValueType<Int32>)m_Int32RVTVP1).IsValueSameAs(m_Int32RVTVP3);
Assert.IsFalse(areEqual, "generic RVTVP.IsValueSameAs is broken (are equal)");
areEqual = ((IReferencedValueType<Int32>)m_Int32RVTVP1).IsValueSameAs(m_Int32RVTVP2);
Assert.IsTrue(areEqual, "generic RVTVP.IsValueSameAs is broken (are not equal)");
////////// Swapping tests.
//// generic swapping tests for IReferencedValueType<T> closed as Int32 on
//// an RVT instantiated as Int32.
((IReferencedValueType<Int32>)m_rVTRInt32TRA1).SwapValues(m_rVTRInt32TRA3);
areEqual = ((IEquatable<IReferencedValueType>)m_rVTRInt32TRA1).Equals(m_rVTRInt32TRA2);
Assert.IsFalse(areEqual, "generic swap is broken (are equal)");
// Put them back and check again.
((IReferencedValueType<Int32>)m_rVTRInt32TRA1).SwapValues(m_rVTRInt32TRA3);
areEqual = ((IEquatable<IReferencedValueType>)m_rVTRInt32TRA1).Equals(m_rVTRInt32TRA2);
Assert.IsTrue(areEqual, "generic swap is broken(are not equal)");
//// non-generic swapping tests for IReferencedValueType on an RVT instantiated as Int32.
((IReferencedValueType)m_rVTRInt32TRA1).SwapValues(m_rVTRInt32TRA3);
areEqual = ((IEquatable<IReferencedValueType>)m_rVTRInt32TRA1).Equals(m_rVTRInt32TRA2);
Assert.IsFalse(areEqual, "non-generic swap is broken (are equal)");
// Swap back just to make sure.
((IReferencedValueType)m_rVTRInt32TRA3).SwapValues(m_rVTRInt32TRA1);
areEqual = ((IEquatable<IReferencedValueType>)m_rVTRInt32TRA1).Equals(m_rVTRInt32TRA2);
Assert.IsTrue(areEqual, "non-generic swap is broken (are not equal)");
//// generic swapping tests for IReferencedValueType<T> closed as Int32 on
//// an RVT instantiated as Int32RVTVP.
((IReferencedValueType<Int32>)m_Int32RVTVP1).SwapValues(m_Int32RVTVP3);
areEqual = ((IEquatable<IReferencedValueType>)m_Int32RVTVP1).Equals(m_Int32RVTVP2);
Assert.IsFalse(areEqual, "generic RVTVP.SwapValues is broken (are equal)");
((IReferencedValueType<Int32>)m_Int32RVTVP3).SwapValues(m_Int32RVTVP1);
areEqual = ((IEquatable<IReferencedValueType>)m_Int32RVTVP1).Equals(m_Int32RVTVP2);
Assert.IsTrue(areEqual, "generic RVTVP.SwapValues is broken (are not equal)");
//// IEquatable tests.
// Two wrapped Int32's with same value should compare identical.
areEqual = ((IEquatable<IReferencedValueType>)m_rVTRInt32TRA1).Equals(m_rVTRInt32TRA2);
Assert.IsTrue(areEqual, "Int32 comparison is broken (0!=0)");
// Two wrapped Int32's with different value should compare nonidentical.
areEqual = ((IEquatable<IReferencedValueType>)m_rVTRInt32TRA1).Equals(m_rVTRInt32TRA3);
Assert.IsFalse(areEqual, "Int32 comparison is broken(0==1)");
}
/// <summary>
/// This test checks our equality methods on wrapped structs to see if they give
/// the right answer.
/// </summary>
[Test(Description = "Level 1 series b tests for ReferencedValueType")]
public void QATester_RunTest_ReferencedValueType_b()
{
// This test is designed to verify RVT.Equals(ValueType). We take one RVT's
// internal BoxedValue and compare it with another RVT. We use our simple
// non-Generic RVT's m_rVT1, m_rVT2 and m_rVT3.
bool areEqual = ((IEquatable<System.ValueType>)m_rVT1).Equals(m_rVT2.BoxedValue);
Assert.IsTrue(areEqual, "Equals(ValueType) is broken ((0,0)!=(0,0))");
// Same deal when they are different.
areEqual = ((IEquatable<System.ValueType>)m_rVT1).Equals(m_rVT3.BoxedValue);
Assert.IsFalse(areEqual, "Equals(ValueType) is broken ((0,0)==(1,1))");
// Try again with our OPs.
areEqual = (m_rVT1 == m_rVT2);
Assert.IsTrue(areEqual, "ReferencedValueType == ReferencedValueType is broken ((0,0)!=(0,0))");
areEqual = !(m_rVT1 != m_rVT3);
Assert.IsFalse(areEqual, "ReferencedValueType != ReferencedValueType is broken ((0,0)==(1,1))");
// One more time with our lopsided OPs.
areEqual = (m_rVT1 == ((IReferencedValueType)m_rVT2));
Assert.IsTrue(areEqual, "ReferencedValueType == IReferencedValueType is broken ((0,0)!=(0,0))");
areEqual = !(m_rVT1 != ((IReferencedValueType)m_rVT3));
Assert.IsFalse(areEqual, "ReferencedValueType != IReferencedValueType is broken ((0,0)==(1,1))");
// This test is pretty simple. Two wrapped structs of the same value
// should compare equal with our equals method even though the internal
// structs don't implement IEquatable. This will call our IEquatable.Equals()
// on the RVT's. Object.Equals() on the structs is supposed to be done with
// reflection to check all the fields. We'll see.......
areEqual = ((IEquatable<IReferencedValueType>)m_rVTRST1).Equals(m_rVTRST2);
Assert.IsTrue(areEqual, "Object.Equals applied to struct's is broken ((0,0)!=(0,0))");
// Well, wadaya' know - it works..... KRM - only tested in MS.......
// Same deal when they are different.
areEqual = ((IEquatable<IReferencedValueType>)m_rVTRST1).Equals(m_rVTRST3);
Assert.IsFalse(areEqual, "Object.Equals applied to struct's is broken ((0,0)==(1,1))");
//// Now test the structs that implement IEquatable.
// First with equatable structs that are the same.
areEqual = ((IEquatable<IReferencedValueType>)m_rVTRST1).Equals(m_rVTRST2);
Assert.IsTrue(areEqual, "RVTEquatableStruct's IEquatable.Equals is broken ((0,0)!=(0,0))");
// Now try equatable structs that are different.
areEqual = ((IEquatable<IReferencedValueType>)m_rVTRST1).Equals(m_rVTRST3);
Assert.IsFalse(areEqual, "RVTEquatableStruct's IEquatable.Equals is broken ((0,0)==(1,1))");
}
/// <summary>
/// This test checks Interlocked OP operation with our RVT's.
/// </summary>
[Test(Description = "Level 1 series c tests for ReferencedValueType")]
public void QATester_RunTest_ReferencedValueType_c()
{
//// We want to see what Interlocked.Compare(T,T,T) does with our RVT's.
// nonEquatable structs first.
m_rVTRST1 = Interlocked.CompareExchange<GenericRVTReferencedStructClass>(ref m_rVTRST1, m_rVTRST2, m_rVTRST3);
// We already know that Our IEquatable on the RVT works from the last experiment,
// so let's use it.
bool areEqual = ((IEquatable<IReferencedValueType>)m_rVTRST1).Equals(m_rVTRST3);
// Unfortunately, following assertion fails. Apparently MS is doing reference
// equality like in the System.Object version and doesn't bother to look for
// IEquatable<T>.
// Assert.IsTrue(areEqual, "CompareExchange not exchanging on equal nonEquatables");
// We'll put this in to let us know if it ever gets working.
Assert.IsFalse(areEqual, "CompareExchanging is exchanging on equal nonEquatables (it's working now!!!!)");
// Put m_rVTRST1 back - just in case it ever works.
m_rVTRST1 = new GenericRVTReferencedStructClass();
// This one should fail.
//m_rVTRST1 = Interlocked.CompareExchange<RVTReferencedStructType>(ref m_rVTRST1, m_rVTRST3, m_rVTRST3);
//areEqual = ((IEquatable<IReferencedValueType>)m_rVTRST1).Equals(m_rVTRST3);
//Assert.AreEqual(areEqual, "CompareExchanging exchanging nonequal nonEquatables");
//// Let's try this again on Hopefully
// it looks for IEquatable..... The exchange should take place if it does.
}
/// <summary>
/// This test demonstrates miscellaneous ways to access RVT's that we don't
/// actually use, but may be useful to folks, nontheless.
/// </summary>
[Test(Description = "Level 1 series a tests for Miscellaneous")]
public void QATester_RunTest_Miscellaneous_a()
{
bool areEqual = false;
////////// Check access to a wrapped Int32 through reflection on the BoxedValue.
// Here we set the wrapped Int32 through reflection on it's box.
m_rVTRInt32TRA1.InnerValue = 1;
areEqual = ((IReferencedValueType<Int32>)m_rVTRInt32TRA1).IsValueSameAs(m_rVTRInt32TRA2);
Assert.IsFalse(areEqual, "TestInt32.InnerValue is broken (not setting)");
m_rVTRInt32TRA1.InnerValue = 0;
areEqual = ((IReferencedValueType<Int32>)m_rVTRInt32TRA1).IsValueSameAs(m_rVTRInt32TRA2);
Assert.IsTrue(areEqual, "TestInt32.InnerValue is broken (not resetting)");
}
#endregion // Quantitative Tests
}
/// <summary>
/// Level 2 tests for functions in ReferencedValueType. These have long loops,
/// but are not supposed to do allocations.
/// </summary>
[TestFixture]
[Category(QAUtils.TestLevel2Name)]
public class QATester_ReferencedValueType_2
{
#region Class Fields
#endregion
/// <summary>
/// Obligatory default constructor.
/// </summary>
public QATester_ReferencedValueType_2()
{
}
/// <summary>
/// Placeholder.
/// </summary>
[TestFixtureSetUp]
public void TestFixtureSetup(){ }
/// <summary>
/// Placeholder.
/// </summary>
[TestFixtureTearDown]
public void TestFixtureTearDown(){ }
#region Qualitative Tests
///////////////////////////////////////////////////////////////////////
// This section contains tests that print to the console to allow visual
// inspection of results and run loops to check allocations with the
// external "CLR Profiler" tool.
///////////////////////////////////////////////////////////////////////
/// <summary>
/// This test demonstrates accessing the CIL RVT's.
/// </summary>
/// <remarks>
/// ////////////////////////////////////////////////////////////////
/// Memory allocation tests for accessing the structure - this should
/// not create any new boxes - CIL version. Profiler should show about
/// 100K or 200K bytes of allocations (MAX) and it should not depend on the
/// loop count.
/// ////////////////////////////////////////////////////////////////
/// </remarks>
[Test(Description = "Level 2 series a tests for CIL RVTs")]
public void QATester_RunTest_CILRVT_a()
{
///////////////////////////////////////////////////////////////////
// Basic tests for the IlUtils lib. - Note -- this is copied from
// QATester_CILUtility fixme (when done with it)!.
///////////////////////////////////////////////////////////////////
// IlUtils.Main(); // fixme remove this line (when done).
// RVT rVT; = null;
// SimpleStruct simpleStruct;
//// Create new RVT with default values.
//// This is the CIL version.
// rVT = new RVT();
// // Create new RVT with default values.
// // Pull out the structure by unboxing.
// simpleStruct = (SimpleStruct)rVT.boxedStruct;
// // Examine a public field.
// int testInt = simpleStruct.i1;
// Console.WriteLine("i1 = " + testInt.ToString());
///////////////////////////////////////////////////////////////////
// Basic tests for the RVT set method - set the internal struct
// without boxing.
///////////////////////////////////////////////////////////////////
// // Create a fresh SimpleStruct from it's parameterized constructor.
// simpleStruct = new SimpleStruct(12, 23);
// // Use RVT's Value set method to set the internal boxed value.
// rVT.set_Value(simpleStruct);
// // Look at it again.
// simpleStruct = (SimpleStruct)rVT.boxedStruct;
// testInt = simpleStruct.i1;
// Console.WriteLine("i1 = " + testInt.ToString());
// // Look at it again.
// simpleStruct = (SimpleStruct)rVT.boxedStruct;
// testInt = simpleStruct.i2;
// Console.WriteLine("i2 = " + testInt.ToString());
///////////////////////////////////////////////////////////////////
// Memory allocation tests for accessing the structure - this should
// not create any new boxes - CIL version.
///////////////////////////////////////////////////////////////////
// Create new RVT with default values.
// This is the CIL version.
//rVT = new RVT();
//SimpleStruct simpleStruct = new SimpleStruct(-1, -1);
//for(int i = 0; i < 1000000; i++) {
// Create a fresh SimpleStruct from it's parameterized constructor.
// simpleStruct = new SimpleStruct(i, i + 1);
// Use RVT's Value set method to set the internal boxed value.
// rVT.set_Value(simpleStruct);
// Pull it out and look at it.
// simpleStruct = (SimpleStruct)rVT.boxedStruct;
// Console.WriteLine(simpleStruct.i1.ToString());
}
/// <summary>
/// This test demonstrates accessing the RVT's through the
/// <see cref="IValueProp<UValueType>"/> interface.
/// </summary>
/// <remarks>
/// ////////////////////////////////////////////////////////////////
/// RVT's instantiated as IValueProp's closed as an Int32 (an Int32RVTVP).
/// This is a memory test for the CLRProfiler.
///
/// When run under the profiler, this test should produce somewhere
/// below 100K or 200K bytes of allocations (MAX) and it should not
/// depend on the loop count.
/// ////////////////////////////////////////////////////////////////
/// </remarks>
[Test(Description = "Level 2 series a tests for IValueProp RVTs")]
public void QATester_RunTest_IVPRVT_a()
{
ReferencedValueType<Int32> m_Int32RVTVP1 = new Int32RVTVP(0);
ReferencedValueType<Int32> m_Int32RVTVP2 = new Int32RVTVP(1);
// Note this is the same Type as the previous lines. Just showing
// that you can handle a closed Generic different ways.
Int32RVTVP m_Int32RVTVP3 = new Int32RVTVP(2);
for(Int32 i = 0; i < 1000000; i++) {
// This should print once. The inequality check uses the facilities
// within ReferencedValueType to inspect the internal ValueType.
//// The following had to be commented out. It will be rereleased as
//// soon as we get the full TypeHandling facilities converted and
//// available. The problem is that the inequality calls into our
//// TypeHandlingUtils.TypeHandlingUtils.DoesSecondTypeInheritFromFirstType
//// method, whose implementation calls into MS's GetInterfaces() method
//// which generates a fresh Type[] array every time - doesn't do
//// any pooling. Our TypeHandlers cache the Interface array on the Type.
//if(m_Int32RVTVP1 != m_Int32RVTVP2) {
// Console.WriteLine("Hey, we're not equal yet!!");
//}
// This line accesses the RVT's internal boxed value through the
// IValueProp interface, avoiding BOXing.
m_Int32RVTVP1.Value = m_Int32RVTVP2.Value;
// Uncomment the next line if you want to see some awful allocations.
// It should be around 20-40 MB or so with 1 million loop iterations.
// Designed to show why you don't want to use an object-based equals
// for your ValueType in Real-Time applications. What is happening
// here is that we are reboxing every time we make the Equals call.
// if(!Equals(m_Int32RVTVP1.Value, m_Int32RVTVP2.Value)) { }
}
}
#endregion // Qualitative Tests
}
/// <summary>
/// Level 5 tests for functions in ReferencedValueType. These have long loops,
/// and do lots of allocations.
/// </summary>
[TestFixture]
[Category(QAUtils.TestLevel5Name)]
public class QATester_ReferencedValueType_5
{
#region Class Fields
#endregion
/// <summary>
/// Obligatory default constructor.
/// </summary>
public QATester_ReferencedValueType_5()
{
}
/// <summary>
/// Placeholder.
/// </summary>
[TestFixtureSetUp]
public void TestFixtureSetup(){ }
/// <summary>
/// Placeholder.
/// </summary>
[TestFixtureTearDown]
public void TestFixtureTearDown(){ }
#region Qualitative Tests
///////////////////////////////////////////////////////////////////////
// This section contains tests that print to the console to allow visual
// inspection of results and run loops to check allocations with the
// external "CLR Profiler" tool.
///////////////////////////////////////////////////////////////////////
/// <summary>
/// This test demonstrates accessing the CSharp RVT's.
/// </summary>
/// <remarks>
/// ////////////////////////////////////////////////////////////////
/// Memory allocation tests for accessing the structure - this should
/// create new BOXes - CSharp version. Profiler should show about 40MB
/// or so allocated.
/// ////////////////////////////////////////////////////////////////
/// </remarks>
[Test(Description = "Level 5 series a tests for CSharp RVTs")]
public void QATester_RunTest_CSharpRVT_a()
{
///////////////////////////////////////////////////////////////////
// Memory allocation tests for accessing the structure - this should
// create new boxes (and bring your system to its knees!!)
// - CSharp version.
///////////////////////////////////////////////////////////////////
// Create new RVT with default values.
//// This is the CSharp version.
RVTCSharp rVT = new RVTCSharp();
SimpleStructCSharp simpleStruct = new SimpleStructCSharp(-1, -1);
for(int i = 0; i < 1000000; i++) {
// Create a fresh SimpleStruct from it's parameterized constructor.
simpleStruct = new SimpleStructCSharp(i, i + 1);
// Use RVT's Value set method to set the internal boxed value.
////// Style 1 - implicit accessors.
rVT.Value = simpleStruct;
rVT.Value = rVT.Value;
////// End Style 1.
////// Style 2 - explicit accessors.
// rVT.set_Value(simpleStruct);
// rVT.set_Value(rVT.get_Value());
////// End Style 2.
// Pull it out and look at it.
simpleStruct = (SimpleStructCSharp)rVT.boxedStruct;
// Console.WriteLine(simpleStruct.i1.ToString());
}
}
#endregion // Qualitative Tests
}
#endregion // Tests
#region Some Example and Test Types
///////////////////////////////////////////////////////////////////////////
//// This region contains a few simple Types that are used for testing and
//// tutorial purposes.
///////////////////////////////////////////////////////////////////////////
#region Test Types for CSharp Implementations of RVT's
///////////////////////////////////////////////////////////////////////////
//// This is designeded to be a set of Types to show the BOXing problem at
//// the most elemental level to show the difference between CSharp and CIL.
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Class containing a CSharp struct that will be accessed through a BOX,
/// thus undergoing BOXing.
/// </summary>
public class RVTCSharp
{
/// <summary>
/// A ValueType reference to a BOXed SimpleStructCSharp.
/// </summary>
public System.ValueType boxedStruct;
/// <summary>
/// Constructor just embeds a default struct.
/// </summary>
public RVTCSharp() { boxedStruct = new SimpleStructCSharp(); }
/// <summary>
/// Constructor embeds a default struct, then sets it's fields.
/// </summary>
/// <param name="i1">First Int32.</param>
/// <param name="i2">Second Int32.</param>
public RVTCSharp(Int32 i1, Int32 i2)
{
SimpleStructCSharp workingStruct = new SimpleStructCSharp();
workingStruct.i1 = i1;
workingStruct.i2 = i2;
// COPY the struct into its HOME in the BOX.
boxedStruct = workingStruct;
}
//// The following method is what Roeder decompiles our CIL version
//// of set_Value into. Note that this method will not compile. We get:
//// "Error 853 Cannot modify the result of an unboxing conversion."
//// This goes to show that you can't always trust decompilers!! If
//// it compiled, we would not have had to use CIL in the first
//// place !!!!
////
//// The problem is, of course, that silly CSharp always translates
//// any cast from a BOXed ValueType to an unBOXed HOME to the
//// equivalent of an "unbox.any" CIL OP.
//public void set_Value(SimpleStruct simpleStruct)
//{
// ((SimpleStruct)this.boxedStruct).i2 = simpleStruct.i2;
// ((SimpleStruct)this.boxedStruct).i1 = simpleStruct.i1;
//}
/////////////////////
/////// Style 1 - Implicit accessors.
/// <summary>
/// Get/Set the internal struct as a normal C# Property.
/// </summary>
public SimpleStructCSharp Value
{
get { return (SimpleStructCSharp)this.boxedStruct; }
// This is the way we must do it in C# - rebox everytime...
set { this.boxedStruct = value; }
}
/////// End Style 1.
/////// Style 2 - explicit accessors.
//public void set_Value(SimpleStructCSharp simpleStruct)
//{
// // This is the way we must do it in C# - rebox everytime...
// this.boxedStruct = simpleStruct;
//}
//public SimpleStructCSharp get_Value()
//{
// return (SimpleStructCSharp)this.boxedStruct;
//}
/////// End Style 2.
}
/// <summary>
/// Another simple Type. This is a struct with two public and one private int.
/// </summary>
public struct SimpleStructCSharp
{
/// <summary>
/// First one.
/// </summary>
public Int32 i1;
/// <summary>
/// Second one.
/// </summary>
public Int32 i2;
/// <summary>
/// This one is private. Can't access this one from C# or CIL either.
/// </summary>
private Int32 i3;
/// <summary>
/// Constructor that sets public fields from args and sets private to default.
/// </summary>
/// <param name="i1">First Int32.</param>
/// <param name="i2">Second Int32.</param>
public SimpleStructCSharp(Int32 i1, Int32 i2)
{
this.i1 = i1;
this.i2 = i2;
// Unlike in CIL, where the "initlocals" keyword does the job, all
// fields must be explicitly initialized.
this.i3 = 0;
}
/// <summary>
/// Set method.
/// </summary>
/// <param name="simpleStructCSharp">
/// The value to set the struct to.
/// </param>
public void set_Value(SimpleStructCSharp simpleStructCSharp)
{
i1 = simpleStructCSharp.i1;
i2 = simpleStructCSharp.i2;
}
}
#endregion // Test Types for CSharp Implementations of RVT's
#endregion // Some Example and Test Types
}