diff --git a/Perspex.UnitTests/Perspex.UnitTests.csproj b/Perspex.UnitTests/Perspex.UnitTests.csproj
index a9d5b5368c..5f26677796 100644
--- a/Perspex.UnitTests/Perspex.UnitTests.csproj
+++ b/Perspex.UnitTests/Perspex.UnitTests.csproj
@@ -72,11 +72,14 @@
+
+
+
diff --git a/Perspex.UnitTests/Styling/ActivatorTests.cs b/Perspex.UnitTests/Styling/ActivatorTests.cs
new file mode 100644
index 0000000000..3e27529bf3
--- /dev/null
+++ b/Perspex.UnitTests/Styling/ActivatorTests.cs
@@ -0,0 +1,109 @@
+namespace Perspex.UnitTests.Styling
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Reactive.Linq;
+ using System.Reactive.Subjects;
+ using System.Text;
+ using System.Threading.Tasks;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using Perspex.Styling;
+ using Activator = Perspex.Styling.Activator;
+
+ [TestClass]
+ public class ActivatorTests
+ {
+ [TestMethod]
+ public void Activator_Should_Follow_Single_Input()
+ {
+ var inputs = new[] { new TestSubject(false) };
+ var target = new Activator(inputs);
+ var result = new TestObserver();
+
+ target.Subscribe(result);
+ Assert.IsFalse(result.GetValue());
+ inputs[0].OnNext(true);
+ Assert.IsTrue(result.GetValue());
+ inputs[0].OnNext(false);
+ Assert.IsFalse(result.GetValue());
+ inputs[0].OnNext(true);
+ Assert.IsTrue(result.GetValue());
+
+ Assert.AreEqual(1, inputs[0].SubscriberCount);
+ }
+
+ [TestMethod]
+ public void Activator_Should_AND_Multiple_Inputs()
+ {
+ var inputs = new[]
+ {
+ new TestSubject(false),
+ new TestSubject(false),
+ new TestSubject(true),
+ };
+ var target = new Activator(inputs);
+ var result = new TestObserver();
+
+ target.Subscribe(result);
+ Assert.IsFalse(result.GetValue());
+ inputs[0].OnNext(true);
+ inputs[1].OnNext(true);
+ Assert.IsTrue(result.GetValue());
+ inputs[0].OnNext(false);
+ Assert.IsFalse(result.GetValue());
+
+ Assert.AreEqual(1, inputs[0].SubscriberCount);
+ Assert.AreEqual(1, inputs[1].SubscriberCount);
+ Assert.AreEqual(1, inputs[2].SubscriberCount);
+ }
+
+ [TestMethod]
+ public void Activator_Should_Unsubscribe_All_When_Input_Completes_On_False()
+ {
+ var inputs = new[]
+ {
+ new TestSubject(false),
+ new TestSubject(false),
+ new TestSubject(true),
+ };
+ var target = new Activator(inputs);
+ var result = new TestObserver();
+
+ target.Subscribe(result);
+ Assert.IsFalse(result.GetValue());
+ inputs[0].OnNext(true);
+ inputs[1].OnNext(true);
+ Assert.IsTrue(result.GetValue());
+ inputs[0].OnNext(false);
+ Assert.IsFalse(result.GetValue());
+ inputs[0].OnCompleted();
+
+ Assert.AreEqual(0, inputs[0].SubscriberCount);
+ Assert.AreEqual(0, inputs[1].SubscriberCount);
+ Assert.AreEqual(0, inputs[2].SubscriberCount);
+ }
+
+ [TestMethod]
+ public void Activator_Should_Not_Unsubscribe_All_When_Input_Completes_On_False()
+ {
+ var inputs = new[]
+ {
+ new TestSubject(false),
+ new TestSubject(false),
+ new TestSubject(true),
+ };
+ var target = new Activator(inputs);
+ var result = new TestObserver();
+
+ target.Subscribe(result);
+ Assert.IsFalse(result.GetValue());
+ inputs[0].OnNext(true);
+ inputs[0].OnCompleted();
+
+ Assert.AreEqual(1, inputs[0].SubscriberCount);
+ Assert.AreEqual(1, inputs[1].SubscriberCount);
+ Assert.AreEqual(1, inputs[2].SubscriberCount);
+ }
+ }
+}
diff --git a/Perspex.UnitTests/TestObserver.cs b/Perspex.UnitTests/TestObserver.cs
new file mode 100644
index 0000000000..aeee1d4cac
--- /dev/null
+++ b/Perspex.UnitTests/TestObserver.cs
@@ -0,0 +1,65 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.UnitTests
+{
+ using System;
+
+ internal class TestObserver : IObserver
+ {
+ private bool hasValue;
+
+ private T value;
+
+ public bool Completed { get; private set; }
+
+ public Exception Error { get; private set; }
+
+ public T GetValue()
+ {
+ if (!this.hasValue)
+ {
+ throw new Exception("Observable provided no value.");
+ }
+
+ if (this.Completed)
+ {
+ throw new Exception("Observable completed unexpectedly.");
+ }
+
+ if (this.Error != null)
+ {
+ throw new Exception("Observable errored unexpectedly.");
+ }
+
+ this.hasValue = false;
+ return value;
+ }
+
+ public void OnCompleted()
+ {
+ this.Completed = true;
+ }
+
+ public void OnError(Exception error)
+ {
+ this.Error = error;
+ }
+
+ public void OnNext(T value)
+ {
+ if (!this.hasValue)
+ {
+ this.value = value;
+ this.hasValue = true;
+ }
+ else
+ {
+ throw new Exception("Observable pushed more than one value.");
+ }
+ }
+ }
+}
diff --git a/Perspex.UnitTests/TestSubject.cs b/Perspex.UnitTests/TestSubject.cs
new file mode 100644
index 0000000000..0a99a5df93
--- /dev/null
+++ b/Perspex.UnitTests/TestSubject.cs
@@ -0,0 +1,60 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.UnitTests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Reactive.Disposables;
+
+ internal class TestSubject : IObserver, IObservable
+ {
+ private T initial;
+
+ private List> subscribers = new List>();
+
+ public TestSubject(T initial)
+ {
+ this.initial = initial;
+ }
+
+ public int SubscriberCount
+ {
+ get { return this.subscribers.Count; }
+ }
+
+ public void OnCompleted()
+ {
+ foreach (IObserver subscriber in this.subscribers.ToArray())
+ {
+ subscriber.OnCompleted();
+ }
+ }
+
+ public void OnError(Exception error)
+ {
+ foreach (IObserver subscriber in this.subscribers.ToArray())
+ {
+ subscriber.OnError(error);
+ }
+ }
+
+ public void OnNext(T value)
+ {
+ foreach (IObserver subscriber in this.subscribers.ToArray())
+ {
+ subscriber.OnNext(value);
+ }
+ }
+
+ public IDisposable Subscribe(IObserver observer)
+ {
+ this.subscribers.Add(observer);
+ observer.OnNext(initial);
+ return Disposable.Create(() => this.subscribers.Remove(observer));
+ }
+ }
+}