GSYMS
GTAGS
ipch
+TestResults
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D} = {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mandycs", "windows\mandycs\mandycs.csproj", "{BF145F89-A268-4619-AAFD-02D63B2685D2}"
+ ProjectSection(ProjectDependencies) = postProject
+ {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D} = {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "windows\tests\tests.csproj", "{9EABF08C-7632-49B2-96FD-D93C623205CA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
+ Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Any CPU.ActiveCfg = Debug|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Win32.ActiveCfg = Debug|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Win32.Build.0 = Debug|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|x64.ActiveCfg = Debug|x64
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|x64.Build.0 = Debug|x64
+ {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Release|Any CPU.ActiveCfg = Release|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Release|Mixed Platforms.Build.0 = Release|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Release|Win32.ActiveCfg = Release|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Release|Win32.Build.0 = Release|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Release|x64.ActiveCfg = Release|x64
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Release|x64.Build.0 = Release|x64
+ {15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Any CPU.ActiveCfg = Debug|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Win32.ActiveCfg = Debug|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Win32.Build.0 = Debug|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|x64.ActiveCfg = Debug|x64
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|x64.Build.0 = Debug|x64
+ {15F60354-A2F4-4C39-91E1-656DA501CE79}.Release|Any CPU.ActiveCfg = Release|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Release|Mixed Platforms.Build.0 = Release|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Release|Win32.ActiveCfg = Release|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Release|Win32.Build.0 = Release|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Release|x64.ActiveCfg = Release|x64
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Release|x64.Build.0 = Release|x64
+ {8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Any CPU.ActiveCfg = Debug|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Win32.ActiveCfg = Debug|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Win32.Build.0 = Debug|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|x64.ActiveCfg = Debug|x64
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|x64.Build.0 = Debug|x64
+ {8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Release|Any CPU.ActiveCfg = Release|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Release|Mixed Platforms.Build.0 = Release|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Release|Win32.ActiveCfg = Release|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Release|Win32.Build.0 = Release|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Release|x64.ActiveCfg = Release|x64
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Release|x64.Build.0 = Release|x64
+ {51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Any CPU.ActiveCfg = Debug|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Win32.ActiveCfg = Debug|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Win32.Build.0 = Debug|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|x64.ActiveCfg = Debug|x64
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|x64.Build.0 = Debug|x64
+ {51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Release|Any CPU.ActiveCfg = Release|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Release|Mixed Platforms.Build.0 = Release|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Release|Win32.ActiveCfg = Release|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Release|Win32.Build.0 = Release|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Release|x64.ActiveCfg = Release|x64
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Release|x64.Build.0 = Release|x64
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Debug|Win32.Build.0 = Debug|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Debug|x64.Build.0 = Debug|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Release|Win32.ActiveCfg = Release|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Release|x64.ActiveCfg = Release|Any CPU
+ {BF145F89-A268-4619-AAFD-02D63B2685D2}.Release|x64.Build.0 = Release|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Debug|Win32.Build.0 = Debug|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Debug|x64.Build.0 = Debug|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Release|Win32.ActiveCfg = Release|Any CPU
+ {9EABF08C-7632-49B2-96FD-D93C623205CA}.Release|x64.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
--- /dev/null
+\feffusing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading;
+
+namespace uk.org.greenend.mandy
+{
+ /// <summary>
+ /// A job in the job queue
+ /// </summary>
+ public class Job
+ {
+ /// <summary>
+ /// Context object (for cancellation)
+ /// </summary>
+ internal object context;
+
+ /// <summary>
+ /// Called in a background thread to run the job.
+ /// </summary>
+ /// <remarks>The default implementation does nothing.</remarks>
+ public virtual void Run()
+ {
+ }
+
+ /// <summary>
+ /// Called from JobQueue.Complete to complete the job.
+ /// </summary>
+ /// <remarks>The default implementation does nothing.</remarks>
+ public virtual void Complete()
+ {
+ }
+
+ /// <summary>
+ /// Called if a job is cancelled without being run
+ /// </summary>
+ /// <remarks>The default implementation does nothing.</remarks>
+ public virtual void Cancel()
+ {
+ }
+ }
+
+ /// <summary>
+ /// The job queue
+ /// </summary>
+ public static class JobQueue
+ {
+ /// <summary>
+ /// Target number of threads
+ /// </summary>
+ /// <remarks>
+ /// <para>Don't change this after adding any jobs - it will be ignored.</para>
+ /// <para>The default is the number of logical CPUs.</para>
+ /// </remarks>
+ public static int Workers = Environment.ProcessorCount;
+
+ /// <summary>
+ /// Set to true when worker threads have been created.
+ /// </summary>
+ private static bool workersCreated = false;
+
+ /// <summary>
+ /// Queued jobs
+ /// </summary>
+ private static LinkedList<Job> jobsPending = new LinkedList<Job>();
+
+ /// <summary>
+ /// Jobs currently being processed
+ /// </summary>
+ private static HashSet<Job> jobsWorking = new HashSet<Job>();
+
+ /// <summary>
+ /// Completed jobs awaiting collection
+ /// </summary>
+ private static LinkedList<Job> jobsComplete = new LinkedList<Job>();
+
+ /// <summary>
+ /// Worker thread
+ /// </summary>
+ static private void Worker()
+ {
+ Monitor.Enter(jobsPending);
+ while (true)
+ {
+ if (jobsPending.Count > 0)
+ {
+ // There is work to be done
+ Job j = jobsPending.First.Value;
+ jobsPending.RemoveFirst();
+ jobsWorking.Add(j);
+ Monitor.Exit(jobsPending);
+ try
+ {
+ j.Run();
+ }
+ catch (Exception)
+ {
+ // Jobs that throw exceptions just lose them.
+ }
+ lock (jobsComplete)
+ {
+ jobsComplete.AddLast(j);
+ Monitor.PulseAll(jobsComplete);
+ }
+ // NB that a job can be in both jobsWorking and jobsComplete
+ // at the same time.
+ Monitor.Enter(jobsPending);
+ jobsWorking.Remove(j);
+ continue;
+ }
+ // If we didn't find anything to do, wait
+ Monitor.Wait(jobsPending);
+ }
+ Monitor.Exit(jobsPending);
+ }
+
+ /// <summary>
+ /// Create a new worker thread
+ /// </summary>
+ /// <remarks><para>Called with lock held.</para></remarks>
+ static private void CreateWorkers()
+ {
+ for (int n = 0; n < Workers; ++n)
+ {
+ Thread newThread = new Thread(new ThreadStart(Worker))
+ {
+ IsBackground = true
+ };
+ newThread.Start();
+ }
+ workersCreated = true;
+ }
+
+ /// <summary>
+ /// Add a job to the queue
+ /// </summary>
+ /// <param name="job">Job to enqueue</param>
+ /// <param name="context">Context information</param>
+ public static void Add(Job job, object context)
+ {
+ lock (jobsPending)
+ {
+ if (!workersCreated)
+ {
+ CreateWorkers();
+ }
+ job.context = context;
+ jobsPending.AddLast(job);
+ Monitor.Pulse(jobsPending);
+ }
+ }
+
+ /// <summary>
+ /// Cancel all pending jobs for a given context
+ /// </summary>
+ /// <param name="context">Context to remove</param>
+ /// <remarks><para>Note that working and completed jobs are not removed.</para></remarks>
+ // TODO but maybe they should be - we could promise that once
+ // Cancel() has been called you'll never see anything from that
+ // context again, so it'd be a guarantee rather than an optimization.
+ public static void Cancel(object context)
+ {
+ List<Job> cancelled = new List<Job>();
+ lock (jobsPending)
+ {
+ for (var node = jobsPending.First; node != null; )
+ {
+ var next = node.Next;
+ if (node.Value.context == context)
+ {
+ jobsPending.Remove(node);
+ // The cancel callback had better be issued outside the lock
+ cancelled.Add(node.Value);
+ }
+ node = next;
+ }
+ }
+ foreach (var job in cancelled)
+ {
+ job.Cancel();
+ }
+ }
+
+ /// <summary>
+ /// Run completion for one or more completed jobs
+ /// </summary>
+ /// <param name="count">Maximum number of job completions to run</param>
+ /// <param name="context">If not null, only complete jobs in this context</param>
+ /// <param name="block">If true, block until all jobs completed, or queue empty</param>
+ /// <returns>The number of jobs that were completed.</returns>
+ /// <remarks><para>The intended use is for Complete to be restricted
+ /// to a single thread. However, it should be safe to call it from multiple
+ /// threads, provided you don't mind your Complete() overrides running
+ /// in unpredictable threads (if context isn't set).</para></remarks>
+ public static int Complete(int count, object context, bool block)
+ {
+ // Special case a count of 0 - it's a stupid value to pass
+ // but it shouldn't cause a hang.
+ if (count == 0)
+ {
+ return 0;
+ }
+ int completed = 0;
+ Monitor.Enter(jobsComplete);
+ while (true)
+ {
+ int completedThisTime = 0;
+ for (var node = jobsComplete.First; count > 0 && node != null; )
+ {
+ var next = node.Next;
+ if (context == null || node.Value.context == context)
+ {
+ // Found a suitable job. Remove it from the list
+ // and then call Complete() on it.
+ jobsComplete.Remove(node);
+ Monitor.Exit(jobsComplete);
+ node.Value.Complete();
+ ++completedThisTime;
+ --count;
+ Monitor.Enter(jobsComplete);
+ }
+ node = next;
+ }
+ completed += completedThisTime;
+ if (count == 0)
+ {
+ // We've done as much work as we were asked to do.
+ break;
+ }
+ if (completedThisTime > 0)
+ {
+ // If we did any work we'll have released the lock, so it's
+ // possible that more work arrived in the meantime. Go back
+ // and check.
+ continue;
+ }
+ if (!block)
+ {
+ // We didn't find any work to do. If we were asked not to block,
+ // exit now.
+ break;
+ }
+ // Wait for more work to arrive.
+ Monitor.Wait(jobsComplete);
+ }
+ Monitor.Exit(jobsComplete);
+ return completed;
+ }
+ }
+}
--- /dev/null
+\feffusing System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("mandycs")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("mandycs")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("834b714d-c664-41f0-b9c4-418d4c5b6e0b")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+\feff<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{BF145F89-A268-4619-AAFD-02D63B2685D2}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>uk.org.greenend.mandy</RootNamespace>
+ <AssemblyName>mandycs</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="JobQueue.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+\feffusing System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using uk.org.greenend.mandy;
+
+namespace tests
+{
+ /// <summary>
+ /// Test job that just records what happened to it
+ /// </summary>
+ class TestJob : Job
+ {
+ public override void Run()
+ {
+ hasRun = true;
+ }
+
+ public override void Complete()
+ {
+ hasCompleted = true;
+ }
+
+ public override void Cancel()
+ {
+ hasCancelled = true;
+ }
+
+ public bool hasRun = false;
+
+ public bool hasCompleted = false;
+
+ public bool hasCancelled = false;
+ }
+
+ /// <summary>
+ /// Tests for JobQueue
+ /// </summary>
+ [TestClass]
+ public class JobQueueTest
+ {
+ /// <summary>
+ /// Test that jobs are run and completed
+ /// </summary>
+ [TestMethod]
+ public void RunJobs()
+ {
+ const int nJobs = 128;
+ List<TestJob> jobs = new List<TestJob>();
+ // Create a collection of jobs and run them
+ for (int i = 0; i < nJobs; ++i)
+ {
+ TestJob job = new TestJob();
+ jobs.Add(job);
+ JobQueue.Add(job, this);
+ }
+ int complete = JobQueue.Complete(nJobs, null, true);
+ Assert.AreEqual(nJobs, complete, string.Format("only {0} jobs completed", complete));
+ for(int i = 0; i < nJobs; ++i)
+ {
+ var job = jobs[i];
+ Assert.AreEqual(true, job.hasRun, string.Format("job {0} wasn't run", i));
+ Assert.AreEqual(true, job.hasCompleted, string.Format("job {0} wasn't completed", i));
+ }
+ }
+
+ /// <summary>
+ /// Test that cancellation works
+ /// </summary>
+ [TestMethod]
+ public void CancelJobs()
+ {
+ const int nJobs = 128;
+ List<TestJob> classOneJobs = new List<TestJob>();
+ List<TestJob> classTwoJobs = new List<TestJob>();
+ for (int i = 0; i < nJobs; ++i)
+ {
+ TestJob job = new TestJob();
+ classOneJobs.Add(job);
+ JobQueue.Add(job, classOneJobs);
+ job = new TestJob();
+ classTwoJobs.Add(job);
+ JobQueue.Add(job, classTwoJobs);
+ }
+ JobQueue.Cancel(classTwoJobs);
+ int complete = JobQueue.Complete(2 * nJobs, null, true);
+ Assert.IsTrue(complete >= nJobs, string.Format("only {0} jobs completed", complete));
+ for (int i = 0; i < nJobs; ++i)
+ {
+ var job = classOneJobs[i];
+ Assert.AreEqual(true, job.hasRun, string.Format("class one job {0} wasn't run", i));
+ Assert.AreEqual(true, job.hasCompleted, string.Format("class one job {0} wasn't completed", i));
+ job = classTwoJobs[i];
+ if (job.hasRun)
+ {
+ Assert.AreEqual(true, job.hasCompleted, string.Format("class two job {0} run but wasn't completed", i));
+ }
+ else
+ {
+ Assert.AreEqual(false, job.hasCompleted, string.Format("class two job {0} didn't run but was completed", i));
+ Assert.AreEqual(true, job.hasCancelled, string.Format("class two job {0} didn't run but wasn't cancelled", i));
+ }
+ }
+ }
+ }
+}
--- /dev/null
+\feffusing System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("tests")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("543a4df3-189a-45fd-8fac-af6f0558fd5f")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+\feff<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{9EABF08C-7632-49B2-96FD-D93C623205CA}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>tests</RootNamespace>
+ <AssemblyName>tests</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
+ <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
+ <IsCodedUITest>False</IsCodedUITest>
+ <TestProjectType>UnitTest</TestProjectType>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ </ItemGroup>
+ <Choose>
+ <When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
+ <ItemGroup>
+ <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ </ItemGroup>
+ </When>
+ <Otherwise>
+ <ItemGroup>
+ <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
+ </ItemGroup>
+ </Otherwise>
+ </Choose>
+ <ItemGroup>
+ <Compile Include="JobQueueTest.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\mandycs\mandycs.csproj">
+ <Project>{bf145f89-a268-4619-aafd-02d63b2685d2}</Project>
+ <Name>mandycs</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Choose>
+ <When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
+ <ItemGroup>
+ <Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <Private>False</Private>
+ </Reference>
+ </ItemGroup>
+ </When>
+ </Choose>
+ <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file