context: #region COPYRIGHT
  
  /*
   *     Copyright 2009-2012 Yuri Astrakhan  (<Firstname><Lastname>@gmail.com)
   *
   *     This file is part of TimeSeriesDb library
   * 
   *  TimeSeriesDb is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   * 
   *  TimeSeriesDb 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 TimeSeriesDb.  If not, see <http://www.gnu.org/licenses/>.
   *
   */
  
  #endregion
  
  using System;
  using System.Collections.Concurrent;
  using System.Collections.Generic;
  using System.Linq.Expressions;
  using System.Reflection;
  using JetBrains.Annotations;
  using NUnit.Framework;
  using NYurik.TimeSeriesDb.Common;
  using NYurik.TimeSeriesDb.Serializers;
  
  namespace NYurik.TimeSeriesDb.Test
  {
      internal static class TestUtils
      {
          private static readonly LinkedList<CacheItem> Items = new LinkedList<CacheItem>();
  
          private static readonly Dictionary<Type, Tuple<Delegate, object>> FuncCache =
              new Dictionary<Type, Tuple<Delegate, object>>();
  
          public static long RoundUpToMultiple(long value, long multiple)
          {
              if (value < 0)
                  throw new ArgumentOutOfRangeException("value", value, "Value must be >= 0");
              if (value == 0)
                  return 0;
              return value - 1 + (multiple - (value - 1)%multiple);
          }
  
          public static void AreNotEqual<T>(T[] expected, T[] values, string description)
          {
              AreNotEqual(new ArraySegment<T>(expected), new ArraySegment<T>(values), description);
          }
  
          public static void AreNotEqual<T>(ArraySegment<T> expected, ArraySegment<T> values, string description = null)
          {
              var s = new DefaultTypeSerializer<T>();
              Assert.IsFalse(s.BinaryArrayCompare(expected, values), description);
          }
  
          public static void AreEqual<T>(T[] expected, T[] values, string description = null)
          {
              AreEqual(new ArraySegment<T>(expected), new ArraySegment<T>(values), description);
          }
  
          public static void AreEqual<T>(ArraySegment<T> expected, ArraySegment<T> values, string description = null)
          {
              var s = new DefaultTypeSerializer<T>();
              Assert.IsTrue(s.BinaryArrayCompare(expected, values), description);
          }
  
          public static T[] Concatenate<T>(params T[][] arrays)
          {
              var res = new List<T>();
              foreach (var a in arrays)
                  res.AddRange(a);
              return res.ToArray();
          }
  
          public static T[] GenerateData<T>(int count, int startFrom, int step = 1)
          {
              string key = String.Format("{0},{1},{2}", typeof (T).FullName, startFrom, step);
              T[] result;
              LinkedListNode<CacheItem> res = Items.Find(new CacheItem(key));
              if (res != null)
              {
                  Items.Remove(res);
  
                  result = (T[]) res.Value.Value;
                  if (result.Length >= count)
                  {
                      T[] rOld = result;
                      result = new T[count];
                      Array.Copy(rOld, result, count);
  
                      Items.AddFirst(res);
                      return result;
                  }
              }
  
              var newObj = GetObjInfo<T>().Item1;
              result = new T[count + 100];
              for (long i = 0; i < count + 100; i++)
                  result[i] = newObj(startFrom + step*i);
  
              Items.AddFirst(new CacheItem(key, result));
              if (Items.Count > 100)
                  Items.RemoveLast();
  
              var rNew = new T[count];
              Array.Copy(result, rNew, count);
              return rNew;
          }
  
          public static IEnumerable<ArraySegment<T>> GenerateDataStream<T>(
              int segSize, int minValue, int maxValue,
              int step = 1)
          {
              if (segSize <= 0)
                  yield break;
  
              for (long i = minValue; i < maxValue; i += segSize)
                  yield return
                      new ArraySegment<T>(GenerateData<T>((int) Math.Min(segSize, maxValue - i), (int) i, step));
          }
  
          [StringFormatMethod("format")]
          public static void CollectionAssertEqual<T>(
              IEnumerable<ArraySegment<T>> expected, IEnumerable<T> actual,
              string format = null, params object[] args)
          {
              CollectionAssertEqual(expected.Stream(), actual, null, format, args);
          }
  
          [StringFormatMethod("format")]
          public static void CollectionAssertEqual<T>(
              IEnumerable<T> expected, IEnumerable<T> actual,
              string format = null, params object[] args)
          {
              CollectionAssertEqual(expected, actual, null, format, args);
          }
  
          [StringFormatMethod("format")]
          public static void CollectionAssertEqual<T>(
              IEnumerable<T> expected, IEnumerable<T> actual,
              Func<T, T, bool> comparer,
              string format = null, params object[] args)
          {
              if (comparer == null)
                  comparer = EqualityComparer<T>.Default.Equals;
  
              string msg = format != null ? String.Format(format + ": ", args) : "";
  
              int count = 0;
              T lastValue = default(T);
  
              string fmt = typeof (T) == typeof (float) || typeof (T) == typeof (double) ? ":r" : "";
  
              using (IEnumerator<T> e = expected.GetEnumerator())
              using (IEnumerator<T> a = actual.GetEnumerator())
              {
                  while (true)
                  {
                      bool eMoved = e.MoveNext();
                      if (eMoved != a.MoveNext())
                      {
                          if (eMoved)
                          {
                              Assert.Fail(
                                  // ReSharper disable FormatStringProblem
                                  "{0}After {1} items, actual list ended, while expected had more starting with {2" +
                                  fmt + "}",
                                  // ReSharper restore FormatStringProblem
                                  msg, count, e.Current);
                          }
                          else
                          {
                              Assert.Fail(
                                  // ReSharper disable FormatStringProblem
                                  "{0}After {1} items, expected list ended, while actual had more starting with {2" +
                                  fmt + "}",
                                  // ReSharper restore FormatStringProblem
                                  msg, count, a.Current);
                          }
                      }
  
                      if (!eMoved)
                          break;
  
                      if (!comparer(e.Current, a.Current))
                      {
                          // ReSharper disable FormatStringProblem
                          string failMsg =
                              String.Format(
                                  "{0}After {1} items, expected value {2" + fmt + "} != actual value {3" + fmt + "}",
                                  msg, count, e.Current, a.Current);
                          if (count > 0)
                              failMsg += String.Format(", lastValue = {0" + fmt + "}", lastValue);
                          // ReSharper restore FormatStringProblem
  
                          Assert.Fail(failMsg);
                      }
  
                      lastValue = a.Current;
                      count++;
                  }
              }
          }
  
          private static readonly ConcurrentDictionary<Tuple<Type, string>, Action> MethodCache =
              new ConcurrentDictionary<Tuple<Type, string>, Action>();
  
          public static void Run<T>(string method)
          {
              var act = MethodCache.GetOrAdd(
                  Tuple.Create(typeof (T), method),
                  v =>
                      {
                          var mi = v.Item1.GetMethod(
                              v.Item2, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                          return (Action) Expression.Lambda(Expression.Call(mi)).Compile();
                      });
  
              act();
          }
  
          public static Tuple<Func<long, T>, T> GetObjInfo<T>()
          {
  
  
  
gt:             Type type = typeof (T);