/// <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>(); }
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>(); }