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 uint _b;
private uint _c;
private uint _d;
private uint _z;
private readonly uint[] _m = new uint[256];
private readonly 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 FeatureTuple
{
private readonly FeatureInfo[] _features;
public int Length => _features.Length;
public FeatureInfo this[int index] {
get {
return _features[index];
}
}
public FeatureTuple(FeatureInfo feature1)
{
_features = new FeatureInfo[1] {
feature1
};
}
public FeatureTuple(FeatureInfo feature1, FeatureInfo feature2)
{
_features = new FeatureInfo[2] {
feature1,
feature2
};
}
}
internal class TestCaseInfo
{
public readonly int[] Features;
public TestCaseInfo(int length)
{
Features = new int[length];
}
public bool IsTupleCovered(FeatureTuple tuple)
{
for (int i = 0; i < tuple.Length; i++) {
if (Features[tuple[i].Dimension] != tuple[i].Feature)
return false;
}
return true;
}
}
internal class PairwiseTestCaseGenerator
{
private FleaRand _prng;
private int[] _dimensions;
private List<FeatureTuple>[][] _uncoveredTuples;
public IEnumerable GetTestCases(int[] dimensions)
{
_prng = new FleaRand(15485863);
_dimensions = dimensions;
CreateAllTuples();
List<TestCaseInfo> list = new List<TestCaseInfo>();
while (true) {
FeatureTuple nextTuple = GetNextTuple();
if (nextTuple == null)
break;
TestCaseInfo testCaseInfo = CreateTestCase(nextTuple);
RemoveTuplesCoveredByTest(testCaseInfo);
list.Add(testCaseInfo);
}
return list;
}
private int GetNextRandomNumber()
{
return (int)(_prng.Next() >> 1);
}
private void CreateAllTuples()
{
_uncoveredTuples = new List<FeatureTuple>[_dimensions.Length][];
for (int i = 0; i < _dimensions.Length; i++) {
_uncoveredTuples[i] = new List<FeatureTuple>[_dimensions[i]];
for (int j = 0; j < _dimensions[i]; j++) {
_uncoveredTuples[i][j] = CreateTuples(i, j);
}
}
}
private List<FeatureTuple> CreateTuples(int dimension, int feature)
{
List<FeatureTuple> list = new List<FeatureTuple>();
list.Add(new FeatureTuple(new FeatureInfo(dimension, feature)));
for (int i = 0; i < _dimensions.Length; i++) {
if (i != dimension) {
for (int j = 0; j < _dimensions[i]; j++) {
list.Add(new FeatureTuple(new FeatureInfo(dimension, feature), new FeatureInfo(i, j)));
}
}
}
return list;
}
private FeatureTuple GetNextTuple()
{
for (int i = 0; i < _uncoveredTuples.Length; i++) {
for (int j = 0; j < _uncoveredTuples[i].Length; j++) {
List<FeatureTuple> list = _uncoveredTuples[i][j];
if (list.Count > 0) {
FeatureTuple result = list[0];
list.RemoveAt(0);
return result;
}
}
}
return null;
}
private TestCaseInfo CreateTestCase(FeatureTuple tuple)
{
TestCaseInfo result = null;
int num = -1;
for (int i = 0; i < 7; i++) {
TestCaseInfo testCaseInfo = CreateRandomTestCase(tuple);
int num2 = MaximizeCoverage(testCaseInfo, tuple);
if (num2 > num) {
result = testCaseInfo;
num = num2;
}
}
return result;
}
private TestCaseInfo CreateRandomTestCase(FeatureTuple tuple)
{
TestCaseInfo testCaseInfo = new TestCaseInfo(_dimensions.Length);
for (int i = 0; i < _dimensions.Length; i++) {
testCaseInfo.Features[i] = GetNextRandomNumber() % _dimensions[i];
}
for (int j = 0; j < tuple.Length; j++) {
testCaseInfo.Features[tuple[j].Dimension] = tuple[j].Feature;
}
return testCaseInfo;
}
private int MaximizeCoverage(TestCaseInfo testCase, FeatureTuple tuple)
{
int num = 1;
int[] mutableDimensions = GetMutableDimensions(tuple);
bool flag;
do {
flag = false;
ScrambleDimensions(mutableDimensions);
foreach (int num2 in mutableDimensions) {
int num3 = CountTuplesCoveredByTest(testCase, num2, testCase.Features[num2]);
int num4 = MaximizeCoverageForDimension(testCase, num2, num3);
num += num4;
if (num4 > num3)
flag = true;
}
} while (flag);
return num;
}
private int[] GetMutableDimensions(FeatureTuple tuple)
{
List<int> list = new List<int>();
bool[] array = new bool[_dimensions.Length];
for (int i = 0; i < tuple.Length; i++) {
array[tuple[i].Dimension] = true;
}
for (int j = 0; j < _dimensions.Length; j++) {
if (!array[j])
list.Add(j);
}
return list.ToArray();
}
private void ScrambleDimensions(int[] dimensions)
{
for (int i = 0; i < dimensions.Length; i++) {
int num = GetNextRandomNumber() % dimensions.Length;
int num2 = dimensions[i];
dimensions[i] = dimensions[num];
dimensions[num] = num2;
}
}
private int MaximizeCoverageForDimension(TestCaseInfo testCase, int dimension, int bestCoverage)
{
List<int> list = new List<int>(_dimensions[dimension]);
for (int i = 0; i < _dimensions[dimension]; i++) {
testCase.Features[dimension] = i;
int num = CountTuplesCoveredByTest(testCase, dimension, i);
if (num >= bestCoverage) {
if (num > bestCoverage) {
bestCoverage = num;
list.Clear();
}
list.Add(i);
}
}
testCase.Features[dimension] = list[GetNextRandomNumber() % list.Count];
return bestCoverage;
}
private int CountTuplesCoveredByTest(TestCaseInfo testCase, int dimension, int feature)
{
int num = 0;
List<FeatureTuple> list = _uncoveredTuples[dimension][feature];
for (int i = 0; i < list.Count; i++) {
if (testCase.IsTupleCovered(list[i]))
num++;
}
return num;
}
private void RemoveTuplesCoveredByTest(TestCaseInfo testCase)
{
for (int i = 0; i < _uncoveredTuples.Length; i++) {
for (int j = 0; j < _uncoveredTuples[i].Length; j++) {
List<FeatureTuple> list = _uncoveredTuples[i][j];
for (int num = list.Count - 1; num >= 0; num--) {
if (testCase.IsTupleCovered(list[num]))
list.RemoveAt(num);
}
}
}
}
}
public IEnumerable<ITestCaseData> GetTestCases(IEnumerable[] sources)
{
List<ITestCaseData> list = new List<ITestCaseData>();
List<object>[] array = CreateValueSet(sources);
int[] dimensions = CreateDimensions(array);
foreach (TestCaseInfo testCase in new PairwiseTestCaseGenerator().GetTestCases(dimensions)) {
object[] array2 = new object[testCase.Features.Length];
for (int i = 0; i < testCase.Features.Length; i++) {
array2[i] = array[i][testCase.Features[i]];
}
TestCaseParameters item = new TestCaseParameters(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;
}
}
}