Skip to content

Commit

Permalink
Fixes unit tests
Browse files Browse the repository at this point in the history
The color tag was omitted from the title bar of a few of the new spectrograms.

Also made it easier to print out C# multi-dimensional array literals. Useful for updating large test values.
  • Loading branch information
atruskie committed Aug 21, 2020
1 parent 2b6821f commit 4fd5f38
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 71 deletions.
1 change: 1 addition & 0 deletions AudioAnalysis.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=dedupe/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DTMF/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ecosounds/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=enumerables/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ffmpeg/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ffprobe/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=flac/@EntryIndexedValue">True</s:Boolean>
Expand Down
3 changes: 2 additions & 1 deletion src/Acoustics.Shared/Acoustics.Shared.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AssemblyTitle>Acoustics.Shared</AssemblyTitle>
Expand Down Expand Up @@ -28,6 +28,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.6" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="morelinq" Version="3.3.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ObjectCloner" Version="2.2.2" />
<PackageReference Include="ObjectCloner.Extensions" Version="2.0.1" />
Expand Down
42 changes: 42 additions & 0 deletions src/Acoustics.Shared/Extensions/ArrayExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
// ReSharper disable once CheckNamespace
namespace System
{
//using MoreLinq;
using static MoreLinq.Extensions.RepeatExtension;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Acoustics.Shared.Extensions;

public static class ArrayExtensions
{
Expand Down Expand Up @@ -105,6 +110,43 @@ public static T[] Print<T>(this T[] array)
return array;
}

/// <summary>
/// Prints a multi-dimensional matrix as a C# literal.
/// </summary>
/// <remarks>Assumes all ranks have a lower bound of zero.</remarks>
/// <typeparam name="T">Cast element items to T before toString is called.</typeparam>
/// <param name="array">The source array to print.</param>
public static string PrintAsLiteral<T>(this Array array)
{
var dimensions = Enumerable.Range(0, array.Rank);
var sizes = dimensions.Select(array.GetLength).ToArray();
//var dimensionsWithSize = dimensions.Zip(sizes);

var last = Enumerable.Range(0, sizes[^1]).ToArray();

// the last dimension we iterate across to generate the literal values
var result = sizes[..^1]
.Select(s => Enumerable.Range(0, s))
.MultiCartesian(FormatValue)
.Join(", ")
.WordWrap(leftPadding: 4, splitOn: "},", keepSplit: true);

return @$"{{
{result}
}}";

string FormatValue(IEnumerable<int> indices)
{
var depth = sizes.Length;
var lineDepth = depth - 1;
var start = "{ ".Repeat(lineDepth).Join();
var end = " }".Repeat(lineDepth).Join();
var value = last.Select(x => (T)array.GetValue(indices.Append(x).ToArray())).Join(", ");

return start + value + end;
}
}

/// <summary>
/// Compares two arrays, matching each element in order using the default Equals method for the array type T.
/// </summary>
Expand Down
77 changes: 77 additions & 0 deletions src/Acoustics.Shared/Extensions/CartesianExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// <copyright file="CartesianExtension.cs" company="QutEcoacoustics">
// All code in this file and all associated files are the copyright and property of the QUT Ecoacoustics Research Group (formerly MQUTeR, and formerly QUT Bioacoustics Research Group).
// </copyright>

namespace Acoustics.Shared.Extensions
{
using System;
using System.Collections.Generic;
using System.Linq;
using MoreLinq.Extensions;

/// <summary>
/// Extensions to the MoreLinq.Cartesian function.
/// </summary>
public static class CartesianExtension
{
/// <summary>
/// Returns the Cartesian product of multiple sequences by combining each element of every set with every other element
/// and applying the user-defined projection to the pair.
/// </summary>
/// <typeparam name="TSource">The type of the elements of <paramref name="enumerables"/>.</typeparam>
/// <typeparam name="TResult">The type of the elements of the result sequence.</typeparam>
/// <param name="enumerables">The sequence of sequences of element.s</param>
/// <param name="resultSelector">A projection function that combines elements from both sequences.</param>
/// <returns>A sequence representing the Cartesian product of the source sequences.</returns>
public static IEnumerable<TResult> MultiCartesian<TSource, TResult>(
this IEnumerable<IEnumerable<TSource>> enumerables,
Func<IEnumerable<TSource>, TResult> resultSelector)
{
if (enumerables == null)
{
throw new ArgumentNullException(nameof(enumerables));
}

if (resultSelector == null)
{
throw new ArgumentNullException(nameof(resultSelector));
}

var enumerators = enumerables
.Select(e => e?.GetEnumerator() ?? throw new ArgumentException("One of the enumerables is null"))
.Pipe(e => e.MoveNext())
.ToArray();

do
{
yield return resultSelector(enumerators.Select(e => e.Current));
} while (MoveNext());

foreach (var enumerator in enumerators)
{
enumerator.Dispose();
}

bool MoveNext()
{
for (var i = enumerators.Length - 1; i >= 0; i--)
{
if (enumerators[i].MoveNext())
{
return true;
}

if (i == 0)
{
continue;
}

enumerators[i].Reset();
enumerators[i].MoveNext();
}

return false;
}
}
}
}
10 changes: 6 additions & 4 deletions src/Acoustics.Shared/Extensions/ExtensionsString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,15 @@ public static string Truncate(this string text, int length, string ellipsis, boo
return text + ellipsis;
}

public static string WordWrap(this string text, int wrapThreshold = 120, int leftPadding = 0)
public static string WordWrap(this string text, int wrapThreshold = 120, int leftPadding = 0, string splitOn = " ", bool keepSplit = false)
{
if (string.IsNullOrEmpty(text))
{
return text;
}

int splitLength = splitOn.Length;

string leftPad = string.Empty.PadRight(leftPadding);

// wrap lines
Expand All @@ -229,16 +231,16 @@ public static string WordWrap(this string text, int wrapThreshold = 120, int lef

while (currentLine.Length > wrapThreshold)
{
int splitPoint = currentLine.Substring(0, wrapThreshold).LastIndexOf(' ');
int splitPoint = currentLine.Substring(0, wrapThreshold).LastIndexOf(splitOn);

if (splitPoint < 0)
{
splitPoint = wrapThreshold; // cuts through a word
}

result.AppendLine(leftPad + currentLine.Substring(0, splitPoint));
result.AppendLine(leftPad + currentLine.Substring(0, splitPoint + (keepSplit ? splitLength : 0)));

currentLine = currentLine.Substring(splitPoint + 1);
currentLine = currentLine.Substring(splitPoint + splitLength);
}

if (currentLine.IsNotWhitespace())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ public static Image<Rgb24> GetOctaveScaleSpectrogram(
//TimeSpan xAxisPixelDuration = TimeSpan.FromSeconds(sgConfig.WindowStep / (double)sgConfig.SampleRate);
//var labelInterval = TimeSpan.FromSeconds(5);
//image = BaseSonogram.FrameSonogram(image, titleBar, startTime, xAxisTicInterval, xAxisPixelDuration, labelInterval);
image = octaveScaleGram.GetImageFullyAnnotated(image, title, freqScale.GridLineLocations);
image = octaveScaleGram.GetImageFullyAnnotated(image, title, freqScale.GridLineLocations, ImageTags[OctaveScaleSpectrogram]);
return image;
}

Expand All @@ -497,8 +497,8 @@ public static Image<Rgb24> GetRibbonSpectrograms(
var imageList = new List<Image<Rgb24>> { image2, spacer, image1 };

var combinedImage = ImageTools.CombineImagesVertically(imageList);
var title = "RIBBON SPECTROGRAMS-Linear32 & Octave20: " + sourceRecordingName;
var image = octaveScaleGram.GetImageFullyAnnotated(combinedImage, title, null);
var title = "RIBBON SPECTROGRAMS-Linear32 & Octave19: " + sourceRecordingName;
var image = octaveScaleGram.GetImageFullyAnnotated(combinedImage, title, null, ImageTags[RibbonSpectrogram]);
return image;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class SpectrogramGeneratorTests : GeneratedImageTest<Rgb24>
{ SpectrogramImageType.AmplitudeSpectrogramLocalContrastNormalization, SpectrogramAmplitude },
};

private static readonly Func<SpectrogramImageType[], string> Name = x => x.Select(x => (int)x).Join("_");
private static readonly Func<SpectrogramImageType[], string> Name = x => x.Select(imageType => (int)imageType).Join("_");

public SpectrogramGeneratorTests()

Expand Down Expand Up @@ -98,7 +98,7 @@ public void TestAudio2Sonogram()
[DynamicData(nameof(AllCombinations), DynamicDataDisplayName = nameof(AllCombinationsTestName))]
public void TestAudio2SonogramCombinations(SpectrogramImageType[] images)
{
const int OneSecondWidth = 24;
const int oneSecondWidth = 24;
var testFile = PathHelper.ResolveAsset("1s_silence.wav");

var config = new SpectrogramGeneratorConfig()
Expand All @@ -108,17 +108,12 @@ public void TestAudio2SonogramCombinations(SpectrogramImageType[] images)

var result = GenerateSpectrogramImages(testFile, config, null);

// save image for debugging purposes
//var flag = images.Aggregate("", (seed, x) => $"{seed}_{(int)x}");
//var path = this.TestOutputDirectory.CombineFile($"audio2sonogram_{flag}.png");
//result.CompositeImage.Save(path);

this.ActualImage = result.CompositeImage;
this.ExtraName = Name(images);

// get expected height
var expectedHeight = images.Select(imageType => All[imageType]).Sum();
Assert.That.ImageIsSize(OneSecondWidth, expectedHeight, this.ActualImage);
Assert.That.ImageIsSize(oneSecondWidth, expectedHeight, this.ActualImage);

// ensure images are in correct order
int y = 0;
Expand Down
Loading

0 comments on commit 4fd5f38

Please sign in to comment.