context: /* This file is part of the db4o object database http://www.db4o.com
  
  Copyright (C) 2004 - 2011  Versant Corporation http://www.versant.com
  
  db4o is free software; you can redistribute it and/or modify it under
  the terms of version 3 of the GNU General Public License as published
  by the Free Software Foundation.
  
  db4o is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  for more details.
  
  You should have received a copy of the GNU General Public License along
  with this program.  If not, see http://www.gnu.org/licenses/. */
  using System;
  using System.Collections.Generic;
  using System.Reflection;
  using System.Runtime.CompilerServices;
  using Db4objects.Db4o.Activation;
  using Db4objects.Db4o.TA;
  using Db4oTool.Tests.TA; // MockActivator
  using Db4oUnit;
  
  public abstract class Named
  {
  	protected string _name;
  
  	public Named(string name)
  	{
  		_name = name;
  	}
  
  	public string Name
  	{
  		get { return _name;  }
  	}
  }
  
  public class ProjectItem : Named
  {
  	public ProjectItem(string name) : base(name)
  	{
  	}
  
  	override public bool Equals(object o)
  	{
  		ProjectItem other = o as ProjectItem;
  		if (other == null) return false;
  
  		// foreign field access
  		return _name == other._name;
  	}
  
  	override public int GetHashCode()
  	{
  		return _name.GetHashCode();
  	}
  }
  
  class Project : ProjectItem
  {
  	public Project(string name) : base(name)
  	{
  	}
  
  	public void UseByRef()
  	{
  		ByRef(ref _name);
  	}
  
  	private void ByRef(ref string name)
  	{
  	}
  }
  
  struct AValueType
  {	
  }
  
  [CompilerGenerated]
  class CompilerGeneratedType
  {
  }
  
  class FilteredOut : IActivatable
  {
  	public string foo;
  
  	public FilteredOut(string foo_)
  	{
  		foo = foo_;
  	}
  
  	[NonSerialized]
  	private IActivator _activator;
  
  	public void Bind(IActivator activator)
  	{
  		_activator = activator;
  	}
  
  	public void Activate(ActivationPurpose purpose)
  	{
  		if (null == _activator) return;
  		_activator.Activate(purpose);
  	}
  }
  
  class CustomActivatable : IActivatable
  {
      [NonSerialized]
      private IActivator _activator;
  
      [NonSerialized]
      public int _mustNotInstrumentMe = 1;
      public int _mustInstrumentAccess = 2;
  
      public void Bind(IActivator activator)
      {
          if (_activator != null || activator == null) throw new InvalidOperationException();
          _activator = activator;
      }
  
      public void Activate(ActivationPurpose purpose)
      {
  		if (null == _activator) return;
  		_activator.Activate(purpose);
      }
  }
  
  class VolatileContainer
  {
  	private volatile int _foo;
  
  	public int Foo
  	{
  		get { return _foo; }
  		set { _foo = value; }
  	}
  }
  
  class GenericContainer<T>
  {
  	private int _foo;
  
  	public int Foo
  	{
  		get { return _foo; }
  		set { _foo = value; }
  	}
  }
  
  class GenericInherited : GenericContainer<int>
  {
  	private int _bar;
  
  	public int Bar
  	{
  		get { return _bar; }
  		set { _bar = value; }
  	}
  }
  
  class GenericContainerN<T1, T2, TN>
  {
  	private int _foo;
  
  	public int Foo
  	{
  		get { return _foo; }
  		set { _foo = value; }
  	}
  }
  
  class GenericFieldContainer
  {
  	private int? _foo;
  
  	public int? Foo
  	{
  		get { return _foo; }
  		set { _foo = value; }
  	}
  }
  
  class GenericFieldOnGenericType<T>
  {
  	private T _foo;
  
  	public T Foo
  	{
  		get { return _foo; }
  		set { _foo = value; }
  	}
  }
  
  class MockActivatable : IActivatable
  {
  	public void Bind(IActivator activator) { }
  	public void Activate(ActivationPurpose purpose) { }
  }
  
  class Tagged
  {
  	public string tags;
  
  	public Tagged(string tags_)
  	{
  		tags = tags_;
  	}
  }
  
  class GenericMethods
  {
  	public static string ConstrainedMethod<T>(T value) where T: Tagged
  	{
  		return value.tags;
  	}
  }
  
  // Ensures ta instrumentation plays nice with the 'switch' bytecode
  class SwitchSubject
  {
  	private string _field1;
  	private string _field2;
  
  	public void Update(int index, string value)
  	{
  		switch (index)
  		{
  			case 1:
  				_field1 = value;
  				break;
  			case 2:
  				_field2 = value;
  				break;
  		}
  	}
  
  	public string Get(int index)
  	{
  		switch (index)
  		{
  			case 1: return _field1;
  			case 2: return _field2;
  		}
  		throw new ArgumentException();
  	}
  }
  
  class SubjectHoldingArray
  {
  	private Tagged[] _taggedArray;
  
  	public Tagged[] Items
  	{
  		get { return _taggedArray; }
  		set { _taggedArray = value; }
  	} 
  }
  
  static class StaticClass
  {
  	private static string _name;
  
  	public static string Name
  	{
  		get
  		{
  			return _name;
  		}
  
  		set
  		{
  			_name = value;
  		}
  	}
  }
  
  class Activity
  {
  	private List<string> _checkpoints = new List<string>();
  
  	public string[] Checkpoints
  	{
  		get { return _checkpoints.ToArray(); }
  	}
  
  	public void Checkpoint(string label)
  	{
  		_checkpoints.Add(label);
  	}
  }
  
  class TryFinallySubject
  {
  	private Activity _activity;
  
  	public TryFinallySubject(Activity activity)
  	{
  		_activity = activity;
  	}
  
  	public string TryFinally(object obj)
  	{
  		string result = "";
  		_activity.Checkpoint("BeforeTry");
  		try
  		{
  			result = obj.ToString();
  			_activity.Checkpoint("Try");
  		}
  		finally
  		{
  			_activity.Checkpoint("Finally");
  		}
  		return result;
  	}
  
  	public object TryCatch(object obj)
  	{
  		object result = null;
  		_activity.Checkpoint("BeforeTry");
  		try
  		{
  			result = obj.ToString();
  			_activity.Checkpoint("Try");
  		}
  		catch (Exception x)
  		{
  			_activity.Checkpoint("Catch");
  			result = x;
  		}
  		finally
  		{
  			_activity.Checkpoint("Finally");
  		}
  		return result;
  	}
  }
  
  class GotoSubject
  {
  	private Activity _activity;
  
  	public GotoSubject(Activity activity)
  	{
  		_activity = activity;
  	}
  
  	public void Run(int count)
  	{
  		_activity.Checkpoint("before");
  	search:
  		_activity.Checkpoint("search");
  		for (int i=0; ; ++i)
  		{
  			if (i < count)
  			{
  				if (count > 1)
  				{
  					--count;
  					goto search;
  				}
  				else
  					break;
  			}
  		}
  	}
  }
  
  class ActivatableInheritedFromNonActivatable : NonActivatableBaseClass
  {
  	override public string ToString()
  	{
  		return base.ToString();
  	}
  
  	override public bool Equals(object o)
  	{
  		NonActivatableBaseClass other = o as NonActivatableBaseClass;
  		return name == other.name;
  	}
  }
  
  class TAInstrumentationSubject : ITestCase
  {
  	public void _TestActivatableInheritedFromNonActivatableCallingSuper()
  	{
  		ActivatableInheritedFromNonActivatable subject = new ActivatableInheritedFromNonActivatable();
  		MockActivator a = ActivatorFor(subject);
  		subject.ToString();
  		Assert.AreEqual(1, a.ReadCount);
  	}
  
  	public void _TestActivatableInheritedFromNonActivatableAccessingSuperField()
  	{
  		ActivatableInheritedFromNonActivatable subject = new ActivatableInheritedFromNonActivatable();
  		MockActivator a = ActivatorFor(subject);
  		Assert.IsTrue(subject.Equals(subject));
  		Assert.AreEqual(2, a.ReadCount);
  	}
  
  	public void TestGoto()
  	{
  		Activity activity = new Activity();
  		GotoSubject subject = new GotoSubject(activity);
  		MockActivator a = ActivatorFor(subject);
  		subject.Run(2);
  		ArrayAssert.AreEqual(new string[] { "before", "search", "search" }, activity.Checkpoints);
  		Assert.AreEqual(3, a.ReadCount);
  	}
  
  	public void TestTryFinally()
  	{
  		Activity activity = new Activity();
  		TryFinallySubject subject = new TryFinallySubject(activity);
  		MockActivator a = ActivatorFor(subject);
  		Assert.AreEqual("foo", subject.TryFinally("foo"));
  		ArrayAssert.AreEqual(new string[] { "BeforeTry", "Try", "Finally" }, activity.Checkpoints);
  		Assert.AreEqual(3, a.ReadCount);
  	}
  
  	public void TestTryCatchWithoutException()
  	{
  		Activity activity = new Activity();
  		TryFinallySubject subject = new TryFinallySubject(activity);
  		MockActivator a = ActivatorFor(subject);
  		Assert.AreEqual("foo", subject.TryCatch("foo"));
  		ArrayAssert.AreEqual(new string[] { "BeforeTry", "Try", "Finally" }, activity.Checkpoints);
  		Assert.AreEqual(3, a.ReadCount);
  	}
  
  	public void TestTryCatchWithException()
  	{
  		Activity activity = new Activity();
  		TryFinallySubject subject = new TryFinallySubject(activity);
  		MockActivator a = ActivatorFor(subject);
  		Assert.IsInstanceOf(typeof(NullReferenceException), subject.TryCatch(null));
  		ArrayAssert.AreEqual(new string[] { "BeforeTry", "Catch", "Finally" }, activity.Checkpoints);
  		Assert.AreEqual(3, a.ReadCount);
  	}
  
  	public void TestSubjectHoldingArray()
  	{
  		SubjectHoldingArray subject = new SubjectHoldingArray();
  		MockActivator a = ActivatorFor(subject);
  		subject.Items = null;
  		Assert.AreEqual(1, a.WriteCount);
  		Assert.AreEqual(null, subject.Items);
  		Assert.AreEqual(1, a.ReadCount);
  	}
  
  	public void TestStaticClassIsNotInstrumented()
  	{
  		Assert.IsFalse(
  			typeof(IActivatable).IsAssignableFrom(typeof(StaticClass)),
  			"Static classes should not be instrumented.");
  	}
  
  	public void TestSwitch()
  	{
  		SwitchSubject subject = new SwitchSubject();
  		MockActivator a = ActivatorFor(subject);
  		subject.Update(1, "foo");
  		Assert.AreEqual(1, a.WriteCount);
  		Assert.AreEqual("foo", subject.Get(1));
  		Assert.AreEqual(1, a.ReadCount);
  
  		subject.Update(2, "bar");
  		Assert.AreEqual(2, a.WriteCount);
  		Assert.AreEqual("bar", subject.Get(2));
  		Assert.AreEqual(2, a.ReadCount);
  	}
  
  	public void TestConstrainedGenericMethod()
  	{
  		Tagged obj = new Tagged("foo, bar");
  		MockActivator a = ActivatorFor(obj);
  		Assert.AreEqual("foo, bar", GenericMethods.ConstrainedMethod(obj));
  		Assert.AreEqual(1, a.ReadCount);
  	}
  
  	public void TestGenericFieldOnGenericType()
  	{
  		GenericFieldOnGenericType<int> obj = new GenericFieldOnGenericType<int>();
  		MockActivator a = ActivatorFor(obj);
  		Assert.AreEqual(0, obj.Foo);
  		Assert.AreEqual(1, a.ReadCount);
  	}
  
  	public void TestGenericInherited()
  	{
  		GenericInherited obj = new GenericInherited();
  		MockActivator a = ActivatorFor(obj);
  		Assert.AreEqual(0, obj.Foo);
  		Assert.AreEqual(1, a.ReadCount);
  		Assert.AreEqual(0, obj.Bar);
  		Assert.AreEqual(2, a.ReadCount);
  	}
  
  	public void TestGenericFieldContainer()
  	{
  		GenericFieldContainer container = new GenericFieldContainer();
  		MockActivator a = ActivatorFor(container);
  		Assert.IsNull(container.Foo);
  		Assert.AreEqual(1, a.ReadCount);
  	}
  
  	public void TestGenericInstrumentation()
  	{
  		GenericContainer<int> container = new GenericContainer<int>();
  		MockActivator a = ActivatorFor(container);
  		Assert.AreEqual(0, container.Foo);
  		Assert.AreEqual(1, a.ReadCount);
  	}
  
  	public void TestArbitraryArityGenericInstrumentation()
  	{
  		GenericContainerN<int, string, int> container = new GenericContainerN<int, string, int>();
  		MockActivator a = ActivatorFor(container);
  		Assert.AreEqual(0, container.Foo);
  		Assert.AreEqual(1, a.ReadCount);
  	}
  
  	public void TestVolatileAccess()
  	{
  		VolatileContainer container = new VolatileContainer();
  		MockActivator a = ActivatorFor(container);
  		Assert.AreEqual(0, container.Foo);
  		Assert.AreEqual(1, a.ReadCount);
  	}
  
  	public void TestIsActivatable()
  	{
          Assert.IsTrue(IsActivatable(typeof(Named)));
          Assert.IsTrue(IsActivatable(typeof(ProjectItem)));
  		Assert.IsTrue(IsActivatable(typeof(Project)));
  	}
  
  	public void TestIActivatableImplementClassIsNotInstrumented()
  	{
  		Assert.AreEqual(0, typeof(MockActivatable).GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Length);
  	}
  
  	public void TestPropertyGetter()
  	{
  		Project p = new Project("test");
  		MockActivator activator = ActivatorFor(p);
  
  		Assert.AreEqual(0, activator.ReadCount);
  		Assert.AreEqual("test", p.Name);
  		Assert.AreEqual(1, activator.ReadCount);
  	}
  
  	public void TestForeignFieldAccess()
  	{
  
gt: 		Project p1 = new Project("test");