Skip to content

Commit

Permalink
#2 Updated unittests and README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
RolandKoenig committed Jan 8, 2023
1 parent 4a3178a commit 718a199
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 49 deletions.
56 changes: 51 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,61 @@
# RolandK.Formats.Gpx <img src="assets/Logo_128.png" width="32" />
### Common Information
## Common Information
A .NET Standard library for reading and writing GPX (GPS Exchange Format) files.
This library was build for my [GpxViewer](https://github.com/RolandKoenig/GpxViewer) project. It is based
on the System.Xml.Serialization.XmlSerializer class and therefore available for .NET Framework and .NET Core projects.

### Build
## Build
[![Continuous integration](https://github.com/RolandKoenig/RolandK.Formats.Gpx/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/RolandKoenig/RolandK.Formats.Gpx/actions/workflows/continuous-integration.yml)

### Feature overview
## Feature overview
- Full document model for gpx files
- Load gpx files
- Write gpx files
- Add custom metadata to gpx files
- Don't lose other custom metadate after loading and saving gpx files
- Add custom xml extensions to gpx files
- Don't lose other custom xml extensions information after loading and saving gpx files

## Samples
### Load GPX file
Load file file (here Kösseine.gpx) and get total count of tracks, routes and waypoints in the file
```csharp
var gpxFile = await GpxFile.LoadAsync("Kösseine.gpx");

var countTracks = gpxFile.Tracks.Count;
var countRoutes = gpxFile.Routes.Count;
var countWaypoints = gpxFile.Waypoints.Count;
```

### Save GPX file
Save a previously loaded / created / modified file
```csharp
await GpxFile.SaveAsync(gpxFile, "MyFile.gpx");
```

### Add custom xml extension
Your have to define your own xml extension types and give them a namespace
```csharp
[XmlType("MyTrackExtension", Namespace = "http://testing.rolandk.net/")]
public class MyTrackExtension
{
public bool AlreadyDone { get; set; } = false;
}
```

Then you have to register these xml extension types and their namespaces to GpxFile.
You should do this somewhere in your startup code of your application.
```csharp
// You have to register your own xml extension types
GpxFile.RegisterExtensionType(typeof(MyTrackExtension));
GpxFile.RegisterNamespace("rktest", "http://testing.rolandk.net/");
```

Now you can access these xml extensions from c# code
```csharp
var gpxFile = await GpxFile.LoadAsync(inStream);
var gpxTrack = gpxFile.Tracks[0];

gpxTrack.Extensions ??= new GpxExtensions();
var myTrackExtension = gpxTrack.Extensions.GetOrCreateExtension<MyTrackExtension>();

myTrackExtension.AlreadyDone = true; // This property comes from our own xml extension
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Xml.Serialization;

namespace RolandK.Formats.Gpx.Tests.FileLoad;

public class GpxFileCustomExtensionsTests
{
[Fact]
public async Task AddCustomMetadata()
{
// Arrange
await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_1.gpx");

// Act
GpxFile.RegisterExtensionType(typeof(MyTrackExtension));
GpxFile.RegisterNamespace("rktest", "http://testing.rolandk.net/");

var originalGpxFile = await GpxFile.LoadAsync(inStream);
var originalGpxTrack = originalGpxFile.Tracks[0];

originalGpxTrack.Extensions ??= new GpxExtensions();
var myTrackExtension = originalGpxTrack.Extensions.GetOrCreateExtension<MyTrackExtension>();

myTrackExtension.AlreadyDone = true;

using var writingMemoryStream = new MemoryStream(1024 * 100);
await GpxFile.SaveAsync(originalGpxFile, writingMemoryStream);

using var readingMemoryStream = new MemoryStream(writingMemoryStream.GetBuffer());
var reloadedFile = await GpxFile.LoadAsync(readingMemoryStream);

// Assert
Assert.Single(reloadedFile.Tracks);

var reloadedTrack = reloadedFile.Tracks[0];
Assert.NotNull(reloadedTrack.Extensions);

var reloadedExtension = reloadedTrack.Extensions.TryGetSingleExtension<MyTrackExtension>();
Assert.NotNull(reloadedExtension);
Assert.True(reloadedExtension.AlreadyDone);
}

[XmlType("MyTrackExtension", Namespace = "http://testing.rolandk.net/")]
public class MyTrackExtension
{
public bool AlreadyDone { get; set; }
}
}
37 changes: 30 additions & 7 deletions src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileLoadAsyncTests.cs
Original file line number Diff line number Diff line change
@@ -1,71 +1,95 @@
using System.Text;
using System.Diagnostics.CodeAnalysis;
using System.Text;

namespace RolandK.Formats.Gpx.Tests.FileLoad;

[SuppressMessage("ReSharper", "RedundantArgumentDefaultValue")]
public class GpxFileLoadAsyncTests
{
[Fact]
public async Task GpxVersion1_1_CompatibilityMode()
{
// Arrange
await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_1.gpx");

// Act
var gpxFile = await GpxFile.LoadAsync(inStream, GpxFileDeserializationMethod.Compatibility);

// Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
Assert.Single(gpxFile.Tracks[0].Segments);
Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}

[Fact]
public async Task GpxVersion1_1_Gpx1_1Mode()
{
// Arrange
await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_1.gpx");

// Act
var gpxFile = await GpxFile.LoadAsync(inStream, GpxFileDeserializationMethod.OnlyGpx1_1);

// Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
Assert.Single(gpxFile.Tracks[0].Segments);
Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}

[Fact]
public async Task GpxVersion1_1_on_xml_1_1()
{
// Arrange
await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_1_on_xml_1_1.gpx");

// Act
var gpxFile = await GpxFile.LoadAsync(inStream, GpxFileDeserializationMethod.Compatibility);

// Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
Assert.Single(gpxFile.Tracks[0].Segments);
Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}

[Fact]
public async Task GpxVersion1_0()
{
// Arrange
await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_0.gpx");

// Act
var gpxFile = await GpxFile.LoadAsync(inStream, GpxFileDeserializationMethod.Compatibility);

// Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
Assert.Single(gpxFile.Tracks[0].Segments);
Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}

[Fact]
public async Task GpxVersion1_0_SaveAs1_1()
{
// Arrange
await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_0.gpx");

// Act
var gpxFile = await GpxFile.LoadAsync(inStream, GpxFileDeserializationMethod.Compatibility);
var outStrBuilder = new StringBuilder(33000);
using (var strWriter = new StringWriter(outStrBuilder))
Expand All @@ -74,11 +98,10 @@ public async Task GpxVersion1_0_SaveAs1_1()
}
var writtenFile = outStrBuilder.ToString();

// Check output
// Assert
Assert.True(writtenFile.Contains("version=\"1.1\""), "Version attribute");
Assert.True(writtenFile.Contains("xmlns=\"http://www.topografix.com/GPX/1/1\""), "Default namespace");

// Check original data
Assert.Equal("1.0", gpxFile.Version);
}
}
37 changes: 30 additions & 7 deletions src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileLoadTests.cs
Original file line number Diff line number Diff line change
@@ -1,71 +1,95 @@
using System.Text;
using System.Diagnostics.CodeAnalysis;
using System.Text;

namespace RolandK.Formats.Gpx.Tests.FileLoad;

[SuppressMessage("ReSharper", "RedundantArgumentDefaultValue")]
public class GpxFileLoadTests
{
[Fact]
public void GpxVersion1_1_CompatibilityMode()
{
// Arrange
using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_1.gpx");

// Act
var gpxFile = GpxFile.Load(inStream, GpxFileDeserializationMethod.Compatibility);

// Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
Assert.Single(gpxFile.Tracks[0].Segments);
Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}

[Fact]
public void GpxVersion1_1_Gpx1_1Mode()
{
// Arrange
using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_1.gpx");

// Act
var gpxFile = GpxFile.Load(inStream, GpxFileDeserializationMethod.OnlyGpx1_1);

// Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
Assert.Single(gpxFile.Tracks[0].Segments);
Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}

[Fact]
public void GpxVersion1_1_on_xml_1_1()
{
// Arrange
using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_1_on_xml_1_1.gpx");

// Act
var gpxFile = GpxFile.Load(inStream, GpxFileDeserializationMethod.Compatibility);

// Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
Assert.Single(gpxFile.Tracks[0].Segments);
Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}

[Fact]
public void GpxVersion1_0()
{
// Arrange
using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_0.gpx");

// Act
var gpxFile = GpxFile.Load(inStream, GpxFileDeserializationMethod.Compatibility);

// Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
Assert.Single(gpxFile.Tracks[0].Segments);
Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}

[Fact]
public void GpxVersion1_0_SaveAs1_1()
{
// Arrange
using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_0.gpx");

// Act
var gpxFile = GpxFile.Load(inStream, GpxFileDeserializationMethod.Compatibility);
var outStrBuilder = new StringBuilder(33000);
using (var strWriter = new StringWriter(outStrBuilder))
Expand All @@ -74,11 +98,10 @@ public void GpxVersion1_0_SaveAs1_1()
}
var writtenFile = outStrBuilder.ToString();

// Check output
// Assert
Assert.True(writtenFile.Contains("version=\"1.1\""), "Version attribute");
Assert.True(writtenFile.Contains("xmlns=\"http://www.topografix.com/GPX/1/1\""), "Default namespace");

// Check original data
Assert.Equal("1.0", gpxFile.Version);
}
}
Loading

0 comments on commit 718a199

Please sign in to comment.