Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,19 @@ jobs:
- name: Regenerate bindings
run: python3 tools/codegen.py "${{ steps.provision.outputs.catalog-path }}"

- name: Regenerate the object layer
run: python3 tools/objectgen.py "${{ steps.provision.outputs.catalog-path }}" --report

- name: Report binding drift
run: git --no-pager diff --stat -- MEOS.NET/Internal || true
run: git --no-pager diff --stat -- MEOS.NET/Internal MEOS.NET/Types/Generated || true

- name: Build solution
run: dotnet build MEOS.NET.sln -c Release

- name: Run tests
run: dotnet test MEOS.NET.sln -c Release --no-build
env:
LD_LIBRARY_PATH: ${{ steps.provision.outputs.libmeos-prefix }}/lib

- name: Smoke-test the FFI
run: dotnet run --project ExampleApp/ExampleApp.csproj -c Release --no-build
Expand Down
39 changes: 39 additions & 0 deletions MEOS.NET.Tests/BorrowedStringTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using MEOS.NET.Enums;
using MEOS.NET.Types.Temporal.Number.Float;

namespace MEOS.NET.Tests
{
/// <summary>
/// The MEOS functions that answer with a `const char *` hand back a pointer
/// into a static table, so the caller reads it and does not free it. Freeing
/// it takes the process down, which is what these read.
/// </summary>
[TestClass]
public class BorrowedStringTests : MeosTest
{
[TestMethod]
public void InterpolationOfALinearSequenceIsRead()
{
TemporalFloat temp = TemporalFloat.FromString("[25.0@2024-12-06, 27.0@2024-12-07]");

Assert.AreEqual(InterpolationType.Linear, temp.Interpolation());
}

[TestMethod]
public void InterpolationOfADiscreteSequenceIsRead()
{
TemporalFloat temp = TemporalFloat.FromString("{25.0@2024-12-06, 27.0@2024-12-07}");

Assert.AreEqual(InterpolationType.Discrete, temp.Interpolation());
}

[TestMethod]
public void TheSameBorrowedNameIsReadableTwice()
{
TemporalFloat first = TemporalFloat.FromString("[25.0@2024-12-06, 27.0@2024-12-07]");
TemporalFloat second = TemporalFloat.FromString("[1.0@2024-12-06, 2.0@2024-12-07]");

Assert.AreEqual(first.Interpolation(), second.Interpolation());
}
}
}
140 changes: 140 additions & 0 deletions MEOS.NET.Tests/GeneratedObjectLayerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using MEOS.NET.Exceptions;
using MEOS.NET.Types.Generated;

namespace MEOS.NET.Tests
{
/// <summary>
/// The object layer generated from the catalog's object model: that a MEOS
/// pointer arrives wrapped in the class its own header names, that the values
/// crossing the boundary are the values MEOS holds, and that a MEOS error
/// reaches the caller as an exception rather than a null.
/// </summary>
[TestClass]
public class GeneratedObjectLayerTests : MeosTest
{
private const string Instant = "25.0@2024-12-06";
private const string Sequence = "[25.0@2024-12-06, 27.0@2024-12-07]";
private const string SpanSetText = "{[8, 10], [11, 12]}";

[TestMethod]
public void InstantTextGivesTheConcreteInstantClass()
{
Temporal? temp = TFloat.In(Instant);

Assert.IsInstanceOfType(temp, typeof(TFloatInst));
}

[TestMethod]
public void SequenceTextGivesTheConcreteSequenceClass()
{
Temporal? temp = TFloat.In(Sequence);

Assert.IsInstanceOfType(temp, typeof(TFloatSeq));
}

[TestMethod]
public void SequenceHoldsItsTwoInstants()
{
Temporal temp = TFloat.In(Sequence)!;

Assert.AreEqual(2, temp.NumInstants());
Assert.AreEqual("Linear", temp.Interp());
}

[TestMethod]
public void StartTimestamptzIsTheMomentTheTextNames()
{
Temporal temp = TFloat.In(Sequence)!;

Assert.AreEqual(new DateTime(2024, 12, 6, 0, 0, 0, DateTimeKind.Utc),
temp.StartTimestamptz().ToUniversalTime());
}

[TestMethod]
public void RestrictingToAnInstantGivesThatInstant()
{
Temporal temp = TFloat.In(Sequence)!;
DateTime start = temp.StartTimestamptz();

Temporal? at = temp.AtTimestamptz(start);

Assert.IsInstanceOfType(at, typeof(TFloatInst));
Assert.AreEqual(1, at!.NumInstants());
}

[TestMethod]
public void ValueSpanOfTheSequenceIsItsFloatExtent()
{
TNumber temp = (TNumber)TFloat.In(Sequence)!;

Span span = temp.ToSpan()!;

Assert.IsInstanceOfType(span, typeof(FloatSpan));
Assert.AreEqual(25.0, ((FloatSpan)span).Lower());
Assert.AreEqual(27.0, ((FloatSpan)span).Upper());
}

[TestMethod]
public void SpanSetTextGivesTheConcreteFloatSpanSet()
{
SpanSet? spanset = FloatSpanSet.In(SpanSetText);

Assert.IsInstanceOfType(spanset, typeof(FloatSpanSet));
Assert.AreEqual(2, spanset!.NumSpans());
}

[TestMethod]
public void EachSpanOfTheSetIsTheSpanTheTextNames()
{
SpanSet spanset = FloatSpanSet.In(SpanSetText)!;

Span?[] spans = spanset.Spanarr();

Assert.AreEqual(2, spans.Length);
Assert.AreEqual(8.0, ((FloatSpan)spans[0]!).Lower());
Assert.AreEqual(10.0, ((FloatSpan)spans[0]!).Upper());
Assert.AreEqual(11.0, ((FloatSpan)spans[1]!).Lower());
Assert.AreEqual(12.0, ((FloatSpan)spans[1]!).Upper());
}

[TestMethod]
public void SpanTextIsWhatTheSpanHolds()
{
SpanSet spanset = FloatSpanSet.In(SpanSetText)!;

Assert.AreEqual("[8, 10]", ((FloatSpan)spanset.StartSpan()!).Out(15));
Assert.AreEqual("[11, 12]", ((FloatSpan)spanset.EndSpan()!).Out(15));
}

[TestMethod]
public void TimeDomainOfTheSequenceIsATstzSpanSet()
{
Temporal temp = TFloat.In(Sequence)!;

SpanSet time = temp.Time()!;

Assert.IsInstanceOfType(time, typeof(TsTzSpanSet));
Assert.AreEqual(1, time.NumSpans());
}

[TestMethod]
public void MakingAnInstantFromAValueAndAMomentReadsBack()
{
DateTime moment = new DateTime(2024, 12, 6, 9, 30, 0, DateTimeKind.Utc);

Temporal instant = TFloatInst.Make(25.0, moment)!;

Assert.IsInstanceOfType(instant, typeof(TFloatInst));
Assert.AreEqual(moment, instant.StartTimestamptz().ToUniversalTime());
}

[TestMethod]
public void MalformedTextRaisesTheMeosError()
{
MEOSException raised = Assert.ThrowsException<MEOSUnspecifiedInternalException>(
() => TFloat.In("e" + Instant));

StringAssert.Contains(raised.Message, "e25.0");
}
}
}
21 changes: 21 additions & 0 deletions MEOS.NET.Tests/MeosTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using MEOS.NET.Lifecycle;

namespace MEOS.NET.Tests
{
/// <summary>
/// The base every test class derives from, so each test runs against an open
/// MEOS session.
///
/// MEOS keeps its session state — the timezone its text I/O reads and writes
/// through, and the error handler — per thread, and the test host runs a test
/// on whichever thread it has free. A session opened once for the assembly
/// therefore reaches the thread that opened it and no other: elsewhere a
/// timestamp is read in the machine's own timezone rather than the suite's,
/// and an error raised there reaches no handler at all.
/// </summary>
public abstract class MeosTest
{
[TestInitialize]
public void OpenMeosSession() => MEOSLifecycle.Initialize("UTC");
}
}
21 changes: 0 additions & 21 deletions MEOS.NET.Tests/TemporalGeometryPointTests.cs

This file was deleted.

33 changes: 33 additions & 0 deletions MEOS.NET/Types/Generated/BigIntSet.g.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#nullable enable

using MEOS.NET.Enums;
using MEOS.NET.Internal;

namespace MEOS.NET.Types.Generated
{
/// <summary>The BigIntSet class of the MEOS object model.</summary>
[System.CodeDom.Compiler.GeneratedCode("MEOS.NET.ObjectGen", "0.1.0")]
public class BigIntSet : Set
{
internal BigIntSet(IntPtr ptr) : base(ptr) { }

public long EndValue()
=> MEOSExposedFunctions.bigintset_end_value(this.Ptr);

public string Out()
=> MEOSExposedFunctions.bigintset_out(this.Ptr);

public Set? ShiftScale(long shift, long width, bool hasshift, bool haswidth)
=> MEOSFactory.WrapSet(MEOSExposedFunctions.bigintset_shift_scale(this.Ptr, shift, width, hasshift, haswidth));

public long StartValue()
=> MEOSExposedFunctions.bigintset_start_value(this.Ptr);

public long[] Values()
=> MEOSExposedFunctions.bigintset_values(this.Ptr);

public static Set? In(string str)
=> MEOSFactory.WrapSet(MEOSExposedFunctions.bigintset_in(str));

}
}
45 changes: 45 additions & 0 deletions MEOS.NET/Types/Generated/BigIntSpan.g.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#nullable enable

using MEOS.NET.Enums;
using MEOS.NET.Internal;

namespace MEOS.NET.Types.Generated
{
/// <summary>The BigIntSpan class of the MEOS object model.</summary>
[System.CodeDom.Compiler.GeneratedCode("MEOS.NET.ObjectGen", "0.1.0")]
public class BigIntSpan : Span
{
internal BigIntSpan(IntPtr ptr) : base(ptr) { }

public Span? Expand(long value)
=> MEOSFactory.WrapSpan(MEOSExposedFunctions.bigintspan_expand(this.Ptr, value));

public long Lower()
=> MEOSExposedFunctions.bigintspan_lower(this.Ptr);

public string Out()
=> MEOSExposedFunctions.bigintspan_out(this.Ptr);

public Span? ShiftScale(long shift, long width, bool hasshift, bool haswidth)
=> MEOSFactory.WrapSpan(MEOSExposedFunctions.bigintspan_shift_scale(this.Ptr, shift, width, hasshift, haswidth));

public Span? ToFloatspan()
=> MEOSFactory.WrapSpan(MEOSExposedFunctions.bigintspan_to_floatspan(this.Ptr));

public Span? ToIntspan()
=> MEOSFactory.WrapSpan(MEOSExposedFunctions.bigintspan_to_intspan(this.Ptr));

public long Upper()
=> MEOSExposedFunctions.bigintspan_upper(this.Ptr);

public long Width()
=> MEOSExposedFunctions.bigintspan_width(this.Ptr);

public static Span? In(string str)
=> MEOSFactory.WrapSpan(MEOSExposedFunctions.bigintspan_in(str));

public static Span? Make(long lower, long upper, bool lower_inc, bool upper_inc)
=> MEOSFactory.WrapSpan(MEOSExposedFunctions.bigintspan_make(lower, upper, lower_inc, upper_inc));

}
}
33 changes: 33 additions & 0 deletions MEOS.NET/Types/Generated/BigIntSpanSet.g.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#nullable enable

using MEOS.NET.Enums;
using MEOS.NET.Internal;

namespace MEOS.NET.Types.Generated
{
/// <summary>The BigIntSpanSet class of the MEOS object model.</summary>
[System.CodeDom.Compiler.GeneratedCode("MEOS.NET.ObjectGen", "0.1.0")]
public class BigIntSpanSet : SpanSet
{
internal BigIntSpanSet(IntPtr ptr) : base(ptr) { }

public long Lower()
=> MEOSExposedFunctions.bigintspanset_lower(this.Ptr);

public string Out()
=> MEOSExposedFunctions.bigintspanset_out(this.Ptr);

public SpanSet? ShiftScale(long shift, long width, bool hasshift, bool haswidth)
=> MEOSFactory.WrapSpanSet(MEOSExposedFunctions.bigintspanset_shift_scale(this.Ptr, shift, width, hasshift, haswidth));

public long Upper()
=> MEOSExposedFunctions.bigintspanset_upper(this.Ptr);

public long Width(bool boundspan)
=> MEOSExposedFunctions.bigintspanset_width(this.Ptr, boundspan);

public static SpanSet? In(string str)
=> MEOSFactory.WrapSpanSet(MEOSExposedFunctions.bigintspanset_in(str));

}
}
15 changes: 15 additions & 0 deletions MEOS.NET/Types/Generated/Box.g.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#nullable enable

using MEOS.NET.Enums;
using MEOS.NET.Internal;

namespace MEOS.NET.Types.Generated
{
/// <summary>Bounding-box family.</summary>
[System.CodeDom.Compiler.GeneratedCode("MEOS.NET.ObjectGen", "0.1.0")]
public class Box : MEOSObject
{
internal Box(IntPtr ptr) : base(ptr) { }

}
}
21 changes: 21 additions & 0 deletions MEOS.NET/Types/Generated/CbufferSet.g.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#nullable enable

using MEOS.NET.Enums;
using MEOS.NET.Internal;

namespace MEOS.NET.Types.Generated
{
/// <summary>The CbufferSet class of the MEOS object model.</summary>
[System.CodeDom.Compiler.GeneratedCode("MEOS.NET.ObjectGen", "0.1.0")]
public class CbufferSet : Set
{
internal CbufferSet(IntPtr ptr) : base(ptr) { }

public string Out(int maxdd)
=> MEOSExposedFunctions.cbufferset_out(this.Ptr, maxdd);

public static Set? In(string str)
=> MEOSFactory.WrapSet(MEOSExposedFunctions.cbufferset_in(str));

}
}
Loading
Loading