PairwiseStrategy
PairwiseStrategy creates test cases by combining the parameter
data so that all possible pairs of data items are used.
using NUnit.Framework.Interfaces;
using System.Collections;
using System.Collections.Generic;
namespace NUnit.Framework.Internal.Builders
{
public class PairwiseStrategy : ICombiningStrategy
{
internal class FleaRand
{
private const int FleaRandSize = 256;
private uint b;
private uint c;
private uint d;
private uint z;
private uint[] m = new uint[256];
private uint[] r = new uint[256];
private uint q;
public FleaRand(uint seed)
{
b = seed;
c = seed;
d = seed;
z = seed;
for (int i = 0; i < m.Length; i++) {
m[i] = seed;
}
for (int j = 0; j < 10; j++) {
Batch();
}
q = 0;
}
public uint Next()
{
if (q == 0) {
Batch();
q = (uint)(r.Length - 1);
} else
q--;
return r[q];
}
private void Batch()
{
uint num = b;
uint num2 = c + ++z;
uint num3 = d;
for (int i = 0; i < r.Length; i++) {
uint num4 = m[(long)num % (long)m.Length];
m[(long)num % (long)m.Length] = num3;
num3 = (num2 << 19) + (num2 >> 13) + num;
num2 = (num ^ m[i]);
num = num4 + num3;
r[i] = num2;
}
b = num;
c = num2;
d = num3;
}
}
internal class FeatureInfo
{
public readonly int Dimension;
public readonly int Feature;
public FeatureInfo(int dimension, int feature)
{
Dimension = dimension;
Feature = feature;
}
}
internal class Tuple
{
private readonly List<FeatureInfo> features = new List<FeatureInfo>();
public int Count => features.Count;
public FeatureInfo this[int index] {
get {
return features[index];
}
}
public void Add(FeatureInfo feature)
{
features.Add(feature);
}
}
internal class TupleCollection
{
private readonly List<Tuple> tuples = new List<Tuple>();
public int Count => tuples.Count;
public Tuple this[int index] {
get {
return tuples[index];
}
}
public void Add(Tuple tuple)
{
tuples.Add(tuple);
}
public void RemoveAt(int index)
{
tuples.RemoveAt(index);
}
}
internal class TestCase
{
public readonly int[] Features;
public TestCase(int numberOfDimensions)
{
Features = new int[numberOfDimensions];
}
public bool IsTupleCovered(Tuple tuple)
{
for (int i = 0; i < tuple.Count; i++) {
if (Features[tuple[i].Dimension] != tuple[i].Feature)
return false;
}
return true;
}
}
internal class TestCaseCollection : IEnumerable
{
private readonly List<TestCase> testCases = new List<TestCase>();
public void Add(TestCase testCase)
{
testCases.Add(testCase);
}
public IEnumerator GetEnumerator()
{
return testCases.GetEnumerator();
}
public bool IsTupleCovered(Tuple tuple)
{
foreach (TestCase testCase in testCases) {
if (testCase.IsTupleCovered(tuple))
return true;
}
return false;
}
}
internal class PairwiseTestCaseGenerator
{
private const int MaxTupleLength = 2;
private readonly FleaRand random = new FleaRand(0);
private readonly int[] dimensions;
private readonly TupleCollection[][] uncoveredTuples;
private readonly int[][] currentTupleLength;
private readonly TestCaseCollection testCases = new TestCaseCollection();
public PairwiseTestCaseGenerator(int[] dimensions)
{
this.dimensions = dimensions;
uncoveredTuples = new TupleCollection[this.dimensions.Length][];
for (int i = 0; i < uncoveredTuples.Length; i++) {
uncoveredTuples[i] = new TupleCollection[this.dimensions[i]];
for (int j = 0; j < this.dimensions[i]; j++) {
uncoveredTuples[i][j] = new TupleCollection();
}
}
currentTupleLength = new int[this.dimensions.Length][];
for (int k = 0; k < this.dimensions.Length; k++) {
currentTupleLength[k] = new int[this.dimensions[k]];
}
}
public IEnumerable GetTestCases()
{
CreateTestCases();
return testCases;
}
private void CreateTestCases()
{
while (true) {
ExtendTupleSet();
Tuple tuple = FindTupleToCover();
if (tuple == null)
break;
TestCase testCase = FindGoodTestCase(tuple);
RemoveTuplesCoveredBy(testCase);
testCases.Add(testCase);
}
}
private void ExtendTupleSet()
{
for (int i = 0; i < dimensions.Length; i++) {
for (int j = 0; j < dimensions[i]; j++) {
ExtendTupleSet(i, j);
}
}
}
private void ExtendTupleSet(int dimension, int feature)
{
if (uncoveredTuples[dimension][feature].Count <= 0 && currentTupleLength[dimension][feature] != 2) {
currentTupleLength[dimension][feature]++;
int num = currentTupleLength[dimension][feature];
if (num == 1) {
Tuple tuple = new Tuple();
tuple.Add(new FeatureInfo(dimension, feature));
if (!testCases.IsTupleCovered(tuple))
uncoveredTuples[dimension][feature].Add(tuple);
} else {
for (int i = 0; i < dimensions.Length; i++) {
for (int j = 0; j < dimensions[i]; j++) {
Tuple tuple2 = new Tuple();
tuple2.Add(new FeatureInfo(i, j));
if (tuple2[0].Dimension != dimension) {
tuple2.Add(new FeatureInfo(dimension, feature));
if (!testCases.IsTupleCovered(tuple2))
uncoveredTuples[dimension][feature].Add(tuple2);
}
}
}
}
}
}
private Tuple FindTupleToCover()
{
int num = 2;
int num2 = 0;
Tuple result = null;
for (int i = 0; i < dimensions.Length; i++) {
for (int j = 0; j < dimensions[i]; j++) {
if (currentTupleLength[i][j] < num) {
num = currentTupleLength[i][j];
num2 = uncoveredTuples[i][j].Count;
result = uncoveredTuples[i][j][0];
} else if (currentTupleLength[i][j] == num && uncoveredTuples[i][j].Count > num2) {
num2 = uncoveredTuples[i][j].Count;
result = uncoveredTuples[i][j][0];
}
}
}
return result;
}
private TestCase FindGoodTestCase(Tuple tuple)
{
TestCase result = null;
int num = -1;
for (int i = 0; i < 5; i++) {
TestCase testCase = new TestCase(dimensions.Length);
int num2 = CreateTestCase(tuple, testCase);
if (num2 > num) {
result = testCase;
num = num2;
}
}
return result;
}
private int CreateTestCase(Tuple tuple, TestCase test)
{
for (int i = 0; i < test.Features.Length; i++) {
test.Features[i] = (int)((long)random.Next() % (long)dimensions[i]);
}
for (int j = 0; j < tuple.Count; j++) {
test.Features[tuple[j].Dimension] = tuple[j].Feature;
}
return MaximizeCoverage(test, tuple);
}
private int MaximizeCoverage(TestCase test, Tuple tuple)
{
int[] mutableDimensions = GetMutableDimensions(tuple);
bool flag;
int num;
do {
flag = false;
num = 1;
for (int num2 = mutableDimensions.Length; num2 > 1; num2--) {
int num3 = (int)((long)random.Next() % (long)num2);
int num4 = mutableDimensions[num2 - 1];
mutableDimensions[num2 - 1] = mutableDimensions[num3];
mutableDimensions[num3] = num4;
}
foreach (int num5 in mutableDimensions) {
List<int> list = new List<int>();
int num6 = CountTuplesCovered(test, num5, test.Features[num5]);
int num7 = currentTupleLength[num5][test.Features[num5]];
for (int j = 0; j < dimensions[num5]; j++) {
test.Features[num5] = j;
int num8 = CountTuplesCovered(test, num5, j);
if (currentTupleLength[num5][j] < num7) {
flag = true;
num7 = currentTupleLength[num5][j];
num6 = num8;
list.Clear();
list.Add(j);
} else if (currentTupleLength[num5][j] == num7 && num8 >= num6) {
if (num8 > num6) {
flag = true;
num6 = num8;
list.Clear();
}
list.Add(j);
}
}
if (list.Count == 1)
test.Features[num5] = list[0];
else
test.Features[num5] = list[(int)((long)random.Next() % (long)list.Count)];
num += num6;
}
} while (flag);
return num;
}
private int[] GetMutableDimensions(Tuple tuple)
{
bool[] array = new bool[dimensions.Length];
for (int i = 0; i < tuple.Count; i++) {
array[tuple[i].Dimension] = true;
}
List<int> list = new List<int>();
for (int j = 0; j < dimensions.Length; j++) {
if (!array[j])
list.Add(j);
}
return list.ToArray();
}
private int CountTuplesCovered(TestCase test, int dimension, int feature)
{
int num = 0;
TupleCollection tupleCollection = uncoveredTuples[dimension][feature];
for (int i = 0; i < tupleCollection.Count; i++) {
if (test.IsTupleCovered(tupleCollection[i]))
num++;
}
return num;
}
private void RemoveTuplesCoveredBy(TestCase testCase)
{
for (int i = 0; i < uncoveredTuples.Length; i++) {
for (int j = 0; j < uncoveredTuples[i].Length; j++) {
TupleCollection tupleCollection = uncoveredTuples[i][j];
for (int num = tupleCollection.Count - 1; num >= 0; num--) {
if (testCase.IsTupleCovered(tupleCollection[num]))
tupleCollection.RemoveAt(num);
}
}
}
}
}
public IEnumerable<ITestCaseData> GetTestCases(IEnumerable[] sources)
{
List<ITestCaseData> list = new List<ITestCaseData>();
List<object>[] array = CreateValueSet(sources);
int[] dimensions = CreateDimensions(array);
IEnumerable testCases = new PairwiseTestCaseGenerator(dimensions).GetTestCases();
foreach (TestCase item2 in testCases) {
object[] array2 = new object[item2.Features.Length];
for (int i = 0; i < item2.Features.Length; i++) {
array2[i] = array[i][item2.Features[i]];
}
ParameterSet item = new ParameterSet(array2);
list.Add(item);
}
return list;
}
private List<object>[] CreateValueSet(IEnumerable[] sources)
{
List<object>[] array = new List<object>[sources.Length];
for (int i = 0; i < array.Length; i++) {
List<object> list = new List<object>();
foreach (object item in sources[i]) {
list.Add(item);
}
array[i] = list;
}
return array;
}
private int[] CreateDimensions(List<object>[] valueSet)
{
int[] array = new int[valueSet.Length];
for (int i = 0; i < valueSet.Length; i++) {
array[i] = valueSet[i].Count;
}
return array;
}
}
}