/// <summary>
        /// Creates an <see cref="ItemDescription"/> from the arguments provided.
        /// </summary>
        /// <param name="analyzedFields">A Dictionary holding the fields and their offsets.</param>
        /// <param name="size">The size of the item type.</param>
        /// <param name="typeName">The name of the type.</param>
        /// <returns></returns>
        static ItemDescription FromAnalysis(IEnumerable <AnalyzedField> analyzedFields, Int32 size, string typeName)
        {
            ItemDescription id = new ItemDescription(DescriptionSource.ItemType);

            id.itemSize     = size;
            id.itemTypeName = typeName;
            if (analyzedFields != null)
            {
                foreach (var af in analyzedFields.OrderBy(fo => fo.Offset))
                {
                    FieldInfo fi = af.FieldPath.Last;

                    var f = id.NewField();
                    f.FieldType   = fi.FieldType.GetFieldType();
                    f.Offset      = af.Offset;
                    f.Name        = af.Name;
                    f.IsTime      = fi.FieldType == typeof(Time);
                    f.IsEventTime = fi.IsDefined <EventTimeAttribute>();
                }
                // if the EventTimeAttribute has not been set on any field, use the first time field as event time
                if (id.EventTimeField == null)
                {
                    var f = id.Fields.FirstOrDefault(ff => ff.IsTime);
                    if (f != null)
                    {
                        f.IsEventTime = true;
                    }
                }
            }
            return(id);
        }
        /// <summary>
        /// Creates a TeaFile, using the specified stream as the underlying storage media.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="ownsStream">If true, the instance returned owns the stream, such that disposing the returned instance also disposes <paramref name="stream"/>.</param>
        /// <param name="contentDescription">The content description.</param>
        /// <param name="nameValues">The name values.</param>
        /// <param name="includeItemDescription">if set to <c>true</c> [include item description].</param>
        /// <returns></returns>
        /// <remarks>
        /// Instead of creating a new <see cref="FileStream"/>, this method takes the <see cref="Stream"/> passed. This provides
        /// more control over the stream, like setting specific <see cref="FileShare"/> attributes. It also allows usage of
        /// alternative storage medias like <see cref="MemoryStream"/>.
        /// </remarks>
        public static TeaFile <T> Create(Stream stream, bool ownsStream, string contentDescription = null, NameValueCollection nameValues = null, bool includeItemDescription = true)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            var tf = new TeaFile <T>();

            try
            {
                tf.core   = new TeaFileCore(stream, ownsStream);
                tf.buffer = new SafeBuffer <T>(stream);
                if (includeItemDescription)
                {
                    tf.Description.ItemDescription = ItemDescription.FromAnalysis <T>();
                }
                tf.Description.ContentDescription = contentDescription;
                tf.Description.NameValues         = nameValues;
                tf.Description.Timescale          = Time.Scale; // The
                tf.core.WriteHeader();
                tf.Flush();
                return(tf);
            }
            catch (Exception)
            {
                tf.Dispose();
                throw;
            }
        }
        public void ExoticCoverage()
        {
            var id = new ItemDescription(DescriptionSource.File);

            Executing.This(() => id.GetFieldByName(null)).Should().Throw <ArgumentNullException>();
            Executing.This(() => id.GetFieldByName("nonexistingfield")).Should().Throw <InvalidOperationException>();
        }
        static TeaFile <T> OpenRead(Stream stream, bool ownsStream, ItemDescriptionElements elementsToValidate)
        {
            var tf = new TeaFile <T>();

            try
            {
                tf.core   = new TeaFileCore(stream, ownsStream);
                tf.buffer = new SafeBuffer <T>(stream);
                tf.core.ReadHeader();

                //  reflecting the current type incurs some cost, so we do it only if we are asked to consider
                //  current item layout to check it against to layout described in the file
                ItemDescription accessorDescription = null;
                if (elementsToValidate != ItemDescriptionElements.None)
                {
                    accessorDescription = ItemDescription.FromAnalysis <T>();
                }
                tf.core.IsAccessibleWith(accessorDescription, elementsToValidate);
                return(tf);
            }
            catch (Exception)
            {
                tf.Dispose();
                throw;
            }
        }
        public void IsAccessible()
        {
            var id1 = ItemDescription.FromAnalysis <Event <OHLCV> >();
            var id2 = ItemDescription.FromAnalysis <Event <OHLCV> >();

            id1.IsAccessibleWith(id2, ItemDescriptionElements.All);
        }
        public void IsAccessibleDetectsDifferentSize()
        {
            var ida  = ItemDescription.FromAnalysis <Event <A> >();
            var ida1 = ItemDescription.FromAnalysis <Event <A2> >();

            ida.IsAccessibleWith(ida1, ItemDescriptionElements.None);
            var ex = Executing.This(() => ida.IsAccessibleWith(ida1, ItemDescriptionElements.ItemSize)).Should().Throw <TypeMismatchException>().Exception;

            Console.WriteLine(ex);
        }
        public void EventTimeAttributeTest()
        {
            var id = ItemDescription.FromAnalysis <Timed1>();

            id.Fields[0].IsEventTime.Should().Be.True();

            id = ItemDescription.FromAnalysis <Timed2>();
            id.Fields[0].IsEventTime.Should().Be.True();
            id.Fields[1].IsEventTime.Should().Be.False();

            id = ItemDescription.FromAnalysis <Timed3>();
            id.Fields[0].IsEventTime.Should().Be.False();
            id.Fields[1].IsEventTime.Should().Be.True();
        }
        public void FieldsOffset_might_fail_dependent_on_Jit_TypeLayout_Decision()
        {
            var id = ItemDescription.FromAnalysis <TOHLCV>();

            // the following assertions might fail, since the layout is determined by the Jit compiler and depends on the runtime
            if (Environment.Is64BitProcess)
            {
                id.Fields.Select(f => f.Offset).Should().Have.SameValuesAs(0, 8, 16, 24, 32, 40);
            }
            else
            {
                id.Fields.Select(f => f.Offset).Should().Have.SameValuesAs(0, 8, 16, 24, 32, 40);
            }
        }
        public unsafe void IsAccessibleDetectsFieldTypeDifference()
        {
            sizeof(A2).Should().Be(20);
            sizeof(FieldTypeChange.A2).Should().Be(20);

            var ida  = ItemDescription.FromAnalysis <A2>();
            var ida2 = ItemDescription.FromAnalysis <FieldTypeChange.A2>();

            ida.IsAccessibleWith(ida2, ItemDescriptionElements.None);
            ida.IsAccessibleWith(ida2, ItemDescriptionElements.ItemName);
            ida.IsAccessibleWith(ida2, ItemDescriptionElements.ItemSize);
            Executing.This(() => ida2.IsAccessibleWith(ida, ItemDescriptionElements.FieldTypes))
            .Should().Throw <TypeMismatchException>()
            .Exception.Source.Should().Be("FieldTypes Check");
        }
        public void TimeSeriesFlag()
        {
            var ida = ItemDescription.FromAnalysis <UnTimed>();

            ida.HasEventTime.Should().Be.False();

            var ida2 = ItemDescription.FromAnalysis <Event <UnTimed> >();

            ida2.HasEventTime.Should().Be.True();

            var ida3 = ItemDescription.FromAnalysis <Event <Timed> >();

            ida3.HasEventTime.Should().Be.True();

            Executing.This(() => ItemDescription.FromAnalysis <Event <DateTimed> >()).Should().Throw <InvalidFieldTypeException>();
        }
示例#11
0
        public void IsAccessibleWith(ItemDescription accessorDescription, ItemDescriptionElements elements)
        {
            // without descriptions in the file we cannot check anything. No warning will be issued in such case,
            // the user is responsible to check that files have descriptions if desired.
            if (this.Description == null)
            {
                return;
            }
            if (this.Description.ItemDescription == null)
            {
                return;
            }

            var fileDescription = this.Description.ItemDescription;

            fileDescription.IsAccessibleWith(accessorDescription, elements);
        }
        public unsafe void Fields()
        {
            var id = ItemDescription.FromAnalysis <TOHLCV>();

            id.ItemTypeName.Should().Be("TOHLCV");
            id.ItemSize.Should().Be.GreaterThanOrEqualTo(sizeof(TOHLCV));
            id.ItemSize.Should().Be.LessThanOrEqualTo(sizeof(TOHLCV) + 8);

            id.Fields.Select(f => f.Name).Should().Have.SameValuesAs("Time", "Open", "High", "Low", "Close", "Volume");
            id.Fields.Select(f => f.Index).Should().Have.SameSequenceAs(0, 1, 2, 3, 4, 5);

            // the following assertions might fail, since the layout is determined by the Jit compiler and depends on the runtime
            if (Environment.Is64BitProcess)
            {
                id.Fields.Select(f => f.Offset).Should().Have.SameValuesAs(0, 8, 16, 24, 32, 40);
            }
            else
            {
                id.Fields.Select(f => f.Offset).Should().Have.SameValuesAs(0, 8, 16, 24, 32, 40);
            }
        }
        static TeaFile <T> OpenWrite(Stream stream, bool ownsStream, ItemDescriptionElements elementsToValidate)
        {
            var tf = new TeaFile <T>();

            try
            {
                tf.buffer = new SafeBuffer <T>(stream);
                tf.core   = new TeaFileCore(stream, ownsStream);
                tf.core.ReadHeader();
                tf.core.IsAccessibleWith(ItemDescription.FromAnalysis <T>(), elementsToValidate);
                // filepointer is at begin of item area. finally, the user might want to read.
                // using filepointer is essential here.
                // check the item api to allow this.
                return(tf);
            }
            catch (Exception)
            {
                tf.Dispose();
                throw;
            }
        }
        public unsafe void IsAccessibleDetectsStructHasNoFieldsException()
        {
            sizeof(A2).Should().Be(20);       // has 2 fields, a, b
            sizeof(Other.A2).Should().Be(20); // an empty struct

            var ida  = ItemDescription.FromAnalysis <A2>();
            var ida2 = new ItemDescription(DescriptionSource.File);

            ida2.ItemSize     = 20;
            ida2.ItemTypeName = "A2";

            ida.IsAccessibleWith(ida2, ItemDescriptionElements.None);
            ida.IsAccessibleWith(ida2, ItemDescriptionElements.ItemName);
            ida.IsAccessibleWith(ida2, ItemDescriptionElements.ItemSize);
            Executing.This(() => ida2.IsAccessibleWith(ida, ItemDescriptionElements.FieldOffsets))
            .Should().Throw <TypeMismatchException>()
            .Exception.Source.Should().Be("No ItemFields");
            Executing.This(() => ida.IsAccessibleWith(ida2, ItemDescriptionElements.FieldOffsets))
            .Should().Throw <TypeMismatchException>()
            .Exception.Source.Should().Be("No ItemFields Accessor");

            // FieldNames checking includes FieldOffset checking, so the exception remains its Source
            Executing.This(() => ida2.IsAccessibleWith(ida, ItemDescriptionElements.FieldNames))
            .Should().Throw <TypeMismatchException>()
            .Exception.Source.Should().Be("No ItemFields");
            Executing.This(() => ida.IsAccessibleWith(ida2, ItemDescriptionElements.FieldNames))
            .Should().Throw <TypeMismatchException>()
            .Exception.Source.Should().Be("No ItemFields Accessor");

            // FieldTypes checking includes FieldOffset checking, so the exception remains its Source
            Executing.This(() => ida2.IsAccessibleWith(ida, ItemDescriptionElements.FieldTypes))
            .Should().Throw <TypeMismatchException>()
            .Exception.Source.Should().Be("No ItemFields");
            Executing.This(() => ida.IsAccessibleWith(ida2, ItemDescriptionElements.FieldTypes))
            .Should().Throw <TypeMismatchException>()
            .Exception.Source.Should().Be("No ItemFields Accessor");
        }
        /// <summary>
        /// Checks it the access description can access a time series based on this ItemDescription.
        /// </summary>
        /// <remarks>
        /// policies:<br></br>
        /// If <paramref name="accessorDescription"/> has no fields, the check will always succeed.<br></br>
        ///
        /// </remarks>
        /// <param name="accessorDescription">ItemDescription that describes the type used to access the file.</param>
        /// <param name="elementsToConsider">The amount of details used for the test.</param>
        /// <exception cref="TypeMismatchException">If the accessor type is not suitable to access the file.</exception>
        public void IsAccessibleWith(ItemDescription accessorDescription, ItemDescriptionElements elementsToConsider)
        {
            if (elementsToConsider.HasFlag(ItemDescriptionElements.ItemName))
            {
                if (this.ItemTypeName != accessorDescription.itemTypeName)
                {
                    throw new TypeMismatchException("ItemNames do not match: '{0}' vs '{1}'".Formatted(this.ItemTypeName, accessorDescription.ItemTypeName), "ItemName Check");
                }
            }
            if (elementsToConsider.HasFlag(ItemDescriptionElements.ItemSize))
            {
                if (this.ItemSize != accessorDescription.ItemSize)
                {
                    throw new TypeMismatchException("ItemSizes do not match: {0} vs {1}".Formatted(this.ItemSize, accessorDescription.ItemSize), "ItemSize Check");
                }
            }

            if (elementsToConsider.HasFlag(ItemDescriptionElements.FieldOffsets))
            {
                if (accessorDescription == null)
                {
                    throw new ArgumentNullException("accessorDescription");
                }
                if (!this.fields.Any())
                {
                    throw new TypeMismatchException("No fields are available in {0} to check field offsets. Empty structs are not supported by this API.".Formatted(this.Source.ToString()), "No ItemFields");
                }
                if (!accessorDescription.fields.Any())
                {
                    throw new TypeMismatchException("No fields are available in {0} to check field offsets. Empty structs are not supported by this API.".Formatted(accessorDescription.Source.ToString()), "No ItemFields Accessor");
                }

                var f = this.Fields.FirstOrDefault(ff => accessorDescription.FindFieldByOffset(ff.Offset) == null);
                if (f != null)
                {
                    throw new TypeMismatchException("Field has no field with matching byte offset:'{0}'".Formatted(f), "FieldOffsets Check");
                }
            }
            if (elementsToConsider.HasFlag(ItemDescriptionElements.FieldNames))
            {
                if (accessorDescription == null)
                {
                    throw new ArgumentNullException("accessorDescription");
                }
                // ItemDescriptionDetails.FieldNames includes ItemDescriptionDetails.FieldOffsets by the definition of ItemDescriptionDetails values!
                var f = this.Fields.FirstOrDefault(ff => accessorDescription.FindFieldByOffset(ff.Offset).Name != ff.Name);
                if (f != null)
                {
                    throw new TypeMismatchException("Fields have different names: '{0}' vs '{1}'".Formatted(f, accessorDescription.FindFieldByOffset(f.Offset).Name), "FieldNames Check");
                }
            }
            if (elementsToConsider.HasFlag(ItemDescriptionElements.FieldTypes))
            {
                if (accessorDescription == null)
                {
                    throw new ArgumentNullException("accessorDescription");
                }
                // ItemDescriptionDetails.FieldNames includes ItemDescriptionDetails.FieldOffsets by the definition of ItemDescriptionDetails values!
                var f = this.Fields.FirstOrDefault(ff => accessorDescription.FindFieldByOffset(ff.Offset).FieldType != ff.FieldType);
                if (f != null)
                {
                    throw new TypeMismatchException("Fields have different types: '{0}' vs '{1}'".Formatted(f, accessorDescription.FindFieldByOffset(f.Offset).Name), "FieldTypes Check");
                }
            }
        }
        public void EventTimeIsSetWithoutEventTimeAttribute()
        {
            ItemDescription id = ItemDescription.FromAnalysis <TOHLCV>();

            id.Fields.Count(f => f.IsEventTime).Should().Be(1);
        }
        public void TheFirstTimeFieldIsUsedAsEventTime()
        {
            var ida = ItemDescription.FromAnalysis <PrivateTimed>();

            ida.HasEventTime.Should().Be.True();
        }
 public void EmptyStructIsNotSupported()
 {
     Executing.This(() => ItemDescription.FromAnalysis <EmptyStruct>()).Should().Throw <ItemException>();
 }