From f6653e007589ab543e553ad333626be191ed030f Mon Sep 17 00:00:00 2001 From: glucaci Date: Mon, 19 Dec 2016 12:12:22 +0100 Subject: [PATCH 01/24] Response from MPD will be specific type. MpdDirectory and MpdFile created. Metadata for MpdFile still to be done. --- LibMpc/Commands/Commands.Database.cs | 56 +- LibMpc/Commands/Commands.Output.cs | 31 +- LibMpc/Commands/Commands.Reflection.cs | 9 +- LibMpc/Commands/IMpcCommand.cs | 12 +- LibMpc/Message/MpdResponse.cs | 6 +- LibMpc/MpdFile.cs | 544 ------------------ LibMpc/MpdOutput.cs | 49 -- LibMpc/Types/MpdDirectory.cs | 70 +++ LibMpc/Types/MpdFile.cs | 73 +++ LibMpc/Types/MpdOutput.cs | 21 + LibMpcTest/LibMpcTest.cs | 29 +- .../short-trouser-pants-zip-closing.mp3 | Bin ...tarting-engine-Ford-Mondeo-Mk-3-diesel.mp3 | Bin .../central-locking-Ford-Mondeo-Mk-3.mp3 | Bin LibMpcTest/Server/mpd.db | 86 +-- 15 files changed, 275 insertions(+), 711 deletions(-) delete mode 100644 LibMpc/MpdFile.cs delete mode 100644 LibMpc/MpdOutput.cs create mode 100644 LibMpc/Types/MpdDirectory.cs create mode 100644 LibMpc/Types/MpdFile.cs create mode 100644 LibMpc/Types/MpdOutput.cs rename LibMpcTest/Server/Music/A long name directory with some spaces/{ => Sub Directory Two}/short-trouser-pants-zip-closing.mp3 (100%) rename LibMpcTest/Server/Music/A long name directory with some spaces/{ => Sub Directory Two}/starting-engine-Ford-Mondeo-Mk-3-diesel.mp3 (100%) rename LibMpcTest/Server/Music/Directory With Spaces/{ => SubDirectory One}/central-locking-Ford-Mondeo-Mk-3.mp3 (100%) diff --git a/LibMpc/Commands/Commands.Database.cs b/LibMpc/Commands/Commands.Database.cs index 9f9844e..1db9e4d 100644 --- a/LibMpc/Commands/Commands.Database.cs +++ b/LibMpc/Commands/Commands.Database.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using System.Linq; +using LibMpc.Types; namespace LibMpc { @@ -12,7 +12,7 @@ namespace LibMpc { // TODO: count - public class Find : IMpcCommand>> + public class Find : IMpcCommand> { private readonly ITag _tag; private readonly string _searchText; @@ -25,22 +25,25 @@ namespace LibMpc public string Value => string.Join(" ", "find", _tag.Value, _searchText); - public IDictionary>> FormatResponse(IList> response) + public IEnumerable FormatResponse(IList> response) { - var results = new Dictionary>> - { - { "files", new List>() } - }; + var results = new List(); + var fileBuilder = new MpdFileBuidler(); foreach (var line in response) { if (line.Key.Equals("file")) { - results["files"].Add(new Dictionary { { "file", line.Value } }); + if (fileBuilder.IsInitialized) + { + results.Add(fileBuilder.Build()); + } + + fileBuilder.Init(line.Value); } else { - results["files"].Last().Add(line.Key, line.Value); + fileBuilder.WithProperty(line.Key, line.Value); } } @@ -59,50 +62,38 @@ namespace LibMpc public string Value => string.Join(" ", "list", _tag); - public IDictionary FormatResponse(IList> response) + public string FormatResponse(IList> response) { - return response.ToDefaultDictionary(); + // TODO: + return response.ToString(); } } // TODO: findadd - public class ListAll : IMpcCommand>>> + public class ListAll : IMpcCommand { public string Value => "listall"; - public IDictionary>>> FormatResponse(IList> response) + public MpdDirectory FormatResponse(IList> response) { - var results = new Dictionary>>> - { - { "directories", new List>>() } - }; - // Add by default the root directory - results["directories"].Add(new Dictionary> - { - { "path", new List() }, - { "files", new List() } - }); + var rootDirectory = new MpdDirectory("/"); foreach (var line in response) { if (line.Key.Equals("file")) { - results["directories"].Last()["files"].Add(line.Value); + rootDirectory.AddFile(line.Value); } if (line.Key.Equals("directory")) { - results["directories"].Add(new Dictionary> - { - { "path", new []{ line.Value } }, - { "files", new List() } - }); + rootDirectory.AddDirectory(line.Value); } } - return results; + return rootDirectory; } } @@ -119,9 +110,10 @@ namespace LibMpc // TODO: Extend command: < update [URI] > public string Value => "update"; - public IDictionary FormatResponse(IList> response) + public string FormatResponse(IList> response) { - return response.ToDefaultDictionary(); + // TODO: + return response.ToString(); } } diff --git a/LibMpc/Commands/Commands.Output.cs b/LibMpc/Commands/Commands.Output.cs index 490428b..3c76ea1 100644 --- a/LibMpc/Commands/Commands.Output.cs +++ b/LibMpc/Commands/Commands.Output.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using LibMpc.Types; namespace LibMpc { @@ -23,9 +24,10 @@ namespace LibMpc public string Value => string.Join(" ", "disableoutput", _outputId); - public IDictionary FormatResponse(IList> response) + public string FormatResponse(IList> response) { - return response.ToDefaultDictionary(); + // TODO: + return response.ToString(); } } @@ -43,9 +45,10 @@ namespace LibMpc public string Value => string.Join(" ", "enableoutput", _outputId); - public IDictionary FormatResponse(IList> response) + public string FormatResponse(IList> response) { - return response.ToDefaultDictionary(); + // TODO: + return response.ToString(); } } @@ -54,29 +57,21 @@ namespace LibMpc /// /// Shows information about all outputs. /// - public class Outputs : IMpcCommand>> + public class Outputs : IMpcCommand> { public string Value => "outputs"; - public IDictionary>> FormatResponse(IList> response) + public IEnumerable FormatResponse(IList> response) { - var result = new Dictionary>> - { - { "outputs", new List>() } - }; + var result = new List(); for (var i = 0; i < response.Count; i += 3) { - var outputId = response[i].Value; + var outputId = int.Parse(response[i].Value); var outputName = response[i + 1].Value; - var outputEnabled = response[i + 2].Value; + var outputEnabled = bool.Parse(response[i + 2].Value); - result["outputs"].Add(new Dictionary - { - {"id", outputId}, - {"name", outputName}, - {"enabled", outputEnabled} - }); + result.Add(new MpdOutput(outputId, outputName, outputEnabled)); } return result; diff --git a/LibMpc/Commands/Commands.Reflection.cs b/LibMpc/Commands/Commands.Reflection.cs index 68ed3c5..9d4506e 100644 --- a/LibMpc/Commands/Commands.Reflection.cs +++ b/LibMpc/Commands/Commands.Reflection.cs @@ -14,16 +14,13 @@ namespace LibMpc // TODO: commands // TODO: notcommands - public class TagTypes : IMpcCommand> + public class TagTypes : IMpcCommand> { public string Value => "tagtypes"; - IDictionary> IMpcCommand>.FormatResponse(IList> response) + public IEnumerable FormatResponse(IList> response) { - var result = new Dictionary> - { - { "tagtypes", response.Where(item => item.Key.Equals("tagtype")).Select(item => item.Value).ToList() } - }; + var result = response.Where(item => item.Key.Equals("tagtype")).Select(item => item.Value); return result; } diff --git a/LibMpc/Commands/IMpcCommand.cs b/LibMpc/Commands/IMpcCommand.cs index 008b1f2..71ae392 100644 --- a/LibMpc/Commands/IMpcCommand.cs +++ b/LibMpc/Commands/IMpcCommand.cs @@ -3,18 +3,10 @@ using System.Linq; namespace LibMpc { - public interface IMpcCommand + public interface IMpcCommand { string Value { get; } - IDictionary FormatResponse(IList> response); - } - - internal static class MpdCommandExtensions - { - public static IDictionary ToDefaultDictionary(this IList> items) - { - return items.ToDictionary(item => item.Key, item => item.Value); - } + T FormatResponse(IList> response); } } \ No newline at end of file diff --git a/LibMpc/Message/MpdResponse.cs b/LibMpc/Message/MpdResponse.cs index 0ad720d..dbe24ad 100644 --- a/LibMpc/Message/MpdResponse.cs +++ b/LibMpc/Message/MpdResponse.cs @@ -6,19 +6,19 @@ namespace LibMpc public interface IMpdResponse { IMpdResponseState State { get; } - IDictionary Body { get; } + T Body { get; } } public class MpdResponse : IMpdResponse { - public MpdResponse(string endLine, IDictionary body, bool connected) + public MpdResponse(string endLine, T body, bool connected) { State = new MpdResponseState(endLine, connected); Body = body; } public IMpdResponseState State { get; } - public IDictionary Body { get; } + public T Body { get; } } public static class CheckNotNullExtension diff --git a/LibMpc/MpdFile.cs b/LibMpc/MpdFile.cs deleted file mode 100644 index 7809ad5..0000000 --- a/LibMpc/MpdFile.cs +++ /dev/null @@ -1,544 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace LibMpc -{ - /// - /// The MpdFile class contains all meta data for a file of the MPD. - /// - public class MpdFile - { - private const string TAG_FILE = "file"; - private const string TAG_TIME = "Time"; - private const string TAG_ARTIST = "Artist"; - private const string TAG_ALBUM = "Album"; - private const string TAG_TITLE = "Title"; - private const string TAG_TRACK = "Track"; - private const string TAG_NAME = "Name"; - private const string TAG_GENRE = "Genre"; - private const string TAG_DATE = "Date"; - private const string TAG_COMPOSER = "Composer"; - private const string TAG_PERFORMER = "Performer"; - private const string TAG_COMMENT = "Comment"; - private const string TAG_DISC = "Disc"; - private const string TAG_POS = "Pos"; - private const string TAG_ID = "Id"; - - private const int NO_TIME = -1; - private const string NO_ALBUM = null; - private const string NO_ARTIST = null; - private const string NO_TITLE = null; - private const string NO_TRACK = null; - private const string NO_NAME = null; - private const string NO_GENRE = null; - private const string NO_DATE = null; - private const string NO_COMPOSER = null; - private const string NO_PERFORMER = null; - private const string NO_COMMENT = null; - private const int NO_DISC = -1; - private const int NO_POS = -1; - private const int NO_ID = -1; - - private readonly string file; - private readonly int time; - private readonly string album; - private readonly string artist; - private readonly string title; - private readonly string track; - private readonly string name; - private readonly string genre; - private readonly string date; - private readonly string composer; - private readonly string performer; - private readonly string comment; - private readonly int disc; - private readonly int pos; - private readonly int id; - /// - /// The name and path of the file. - /// - public string File { get { return this.file; } } - /// - /// The length of the file in seconds. - /// - public int Time { get { return this.time; } } - /// - /// The album of the file. - /// - public string Album { get { return this.album; } } - /// - /// The artist of the file. - /// - public string Artist { get { return this.artist; } } - /// - /// The title of the file. - /// - public string Title { get { return this.title; } } - /// - /// The value of the track property of the file. - /// - public string Track { get { return this.track; } } - /// - /// The name of the song. - /// - public string Name { get { return this.name; } } - /// - /// The genre of the song. - /// - public string Genre { get { return this.genre; } } - /// - /// The date the song was released. - /// - public string Date { get { return this.date; } } - /// - /// The composer of the song. - /// - public string Composer { get { return this.composer; } } - /// - /// The performer of the song. - /// - public string Performer { get { return this.performer; } } - /// - /// A comment to the file. - /// - public string Comment { get { return this.comment; } } - /// - /// The number of the disc on a multidisc album. - /// - public int Disc { get { return this.disc; } } - /// - /// The index of the file in a playlist. - /// - public int Pos { get { return this.pos; } } - /// - /// The id of the file in a playlist. - /// - public int Id { get { return this.id; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasTime { get { return this.time != NO_TIME; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasAlbum { get { return this.album != NO_ALBUM; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasArtist { get { return this.artist != NO_ARTIST; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasTitle { get { return this.title != NO_TITLE; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasTrack { get { return this.track != NO_TRACK; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasName { get { return this.name != NO_NAME; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasGenre { get { return this.genre != NO_GENRE; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasDate { get { return this.date != NO_DATE; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasComposer { get { return this.composer != NO_COMPOSER; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasPerformer { get { return this.performer != NO_PERFORMER; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasComment { get { return this.comment != NO_COMMENT; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasDisc { get { return this.disc != NO_DISC; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasPos { get { return this.pos != NO_POS; } } - /// - /// If the MpdFile has the property set. - /// - public bool HasId { get { return this.id != NO_ID; } } - /// - /// Creates a new MpdFile. - /// - /// The name and path of the file. - /// The length of the file in seconds. - /// The album of the file. - /// The artist of the file. - /// The title of the file. - /// The value of the track property of the file. - /// The name of the song. - /// The genre of the song. - /// The date the song was released. - /// The composer of the song. - /// The performer of the song. - /// A comment to the file. - /// The number of the disc on a multidisc album. - /// The index of the file in a playlist. - /// The id of the file in a playlist. - public MpdFile(string file, - int time, - string album, - string artist, - string title, - string track, - string name, - string genre, - string date, - string composer, - string performer, - string comment, - int disc, - int pos, - int id) - { - if (file == null) - throw new ArgumentNullException("file"); - - this.file = file; - this.time = time; - this.album = album; - this.artist = artist; - this.title = title; - this.track = track; - this.name = name; - this.genre = genre; - this.date = date; - this.composer = composer; - this.performer = performer; - this.comment = comment; - this.disc = disc; - this.pos = pos; - this.id = id; - } - /// - /// A string containing all the properties of the file. - /// - /// - public override string ToString() - { - StringBuilder builder = new StringBuilder(); - - appendString(builder, TAG_FILE, this.file); - if (this.HasTime) - appendInt(builder, TAG_TIME, this.time); - if (this.HasAlbum) - appendString(builder, TAG_ALBUM, this.album); - if (this.HasArtist) - appendString(builder, TAG_ARTIST, this.artist); - if (this.HasTitle) - appendString(builder, TAG_TITLE, this.title); - if (this.HasTrack) - appendString(builder, TAG_TRACK, this.track); - if (this.HasName) - appendString(builder, TAG_NAME, this.name); - if (this.HasGenre) - appendString(builder, TAG_GENRE, this.genre); - if (this.HasDate) - appendString(builder, TAG_DATE, this.date); - if (this.HasComposer) - appendString(builder, TAG_COMPOSER, this.composer); - if (this.HasPerformer) - appendString(builder, TAG_PERFORMER, this.performer); - if (this.HasComment) - appendString(builder, TAG_COMMENT, this.comment); - if (this.HasDisc) - appendInt(builder, TAG_DISC, this.disc); - if (this.HasPos) - appendInt(builder, TAG_POS, this.pos); - if (this.HasId) - appendInt(builder, TAG_ID, this.id); - - return builder.ToString(); - } - - private static void appendString(StringBuilder builder, string name, string value) - { - builder.Append(name); - builder.Append(": "); - builder.Append(value); - builder.AppendLine(); - } - - private static void appendInt(StringBuilder builder, string name, int value) - { - builder.Append(name); - builder.Append(": "); - builder.Append(value); - builder.AppendLine(); - } - /* - /// - /// Returns a MpdFile object from a MpdResponse object. - /// - /// The response of the MPD server. - /// A new MpdFile object build from the MpdResponse object. - public static MpdFile build(MpdResponse response) - { - if (response == null) - throw new ArgumentNullException("response"); - - string file = null; - int time = NO_TIME; - string album = NO_ALBUM; - string artist = NO_ARTIST; - string title = NO_TITLE; - string track = NO_TRACK; - string name = NO_NAME; - string genre = NO_GENRE; - string date = NO_DATE; - string composer = NO_COMPOSER; - string performer = NO_PERFORMER; - string comment = NO_COMMENT; - int disc = NO_DISC; - int pos = NO_POS; - int id = NO_ID; - - - foreach (KeyValuePair line in response) - { - if( line.Key != null ) - switch (line.Key) - { - case TAG_FILE: - file = line.Value; - break; - case TAG_TIME: - int tryTime; - if( int.TryParse( line.Value, out tryTime ) ) - time = tryTime; - break; - case TAG_ALBUM: - album = line.Value; - break; - case TAG_ARTIST: - artist = line.Value; - break; - case TAG_TITLE: - title = line.Value; - break; - case TAG_TRACK: - track = line.Value; - break; - case TAG_NAME: - name = line.Value; - break; - case TAG_GENRE: - genre = line.Value; - break; - case TAG_DATE: - date = line.Value; - break; - case TAG_COMPOSER: - composer = line.Value; - break; - case TAG_PERFORMER: - performer = line.Value; - break; - case TAG_COMMENT: - comment = line.Value; - break; - case TAG_DISC: - int tryDisc; - if (int.TryParse(line.Value, out tryDisc)) - disc = tryDisc; - break; - case TAG_POS: - int tryPos; - if (int.TryParse(line.Value, out tryPos)) - pos = tryPos; - break; - case TAG_ID: - int tryId; - if (int.TryParse(line.Value, out tryId)) - id = tryId; - break; - } - } - - if (file == null) - return null; - else - return new MpdFile( - file, - time, - album, - artist, - title, - track, - name, - genre, - date, - composer, - performer, - comment, - disc, - pos, - id); - } - /// - /// Builds a list of MpdFile objects from a MpdResponse object. - /// - /// The MpdResponse object to build the list of MpdFiles from. - /// A list ob MpdFiles built from the MpdResponse object. - public static List buildList(MpdResponse response) - { - if (response == null) - throw new ArgumentNullException("response"); - - List ret = new List(); - - string file = null; - int time = NO_TIME; - string album = NO_ALBUM; - string artist = NO_ARTIST; - string title = NO_TITLE; - string track = NO_TRACK; - string name = NO_NAME; - string genre = NO_GENRE; - string date = NO_DATE; - string composer = NO_COMPOSER; - string performer = NO_PERFORMER; - string comment = NO_COMMENT; - int disc = NO_DISC; - int pos = NO_POS; - int id = NO_ID; - - - foreach (KeyValuePair line in response) - { - if( line.Key != null ) - switch (line.Key) - { - case TAG_FILE: - if( file != null ) - ret.Add( new MpdFile( - file, - time, - album, - artist, - title, - track, - name, - genre, - date, - composer, - performer, - comment, - disc, - pos, - id ) ); - - file = line.Value; - - time = NO_TIME; - album = NO_ALBUM; - artist = NO_ARTIST; - title = NO_TITLE; - track = NO_TRACK; - name = NO_NAME; - genre = NO_GENRE; - date = NO_DATE; - composer = NO_COMPOSER; - performer = NO_PERFORMER; - comment = NO_COMMENT; - disc = NO_DISC; - pos = NO_POS; - id = NO_ID; - - break; - case TAG_TIME: - int tryTime; - if( int.TryParse( line.Value, out tryTime ) ) - time = tryTime; - break; - case TAG_ALBUM: - album = line.Value; - break; - case TAG_ARTIST: - artist = line.Value; - break; - case TAG_TITLE: - title = line.Value; - break; - case TAG_TRACK: - track = line.Value; - - // TODO: - int tryTrack; - if (int.TryParse(line.Value, out tryTrack)) - track = tryTrack; - - break; - case TAG_NAME: - name = line.Value; - break; - case TAG_GENRE: - genre = line.Value; - break; - case TAG_DATE: - date = line.Value; - break; - case TAG_COMPOSER: - composer = line.Value; - break; - case TAG_PERFORMER: - performer = line.Value; - break; - case TAG_COMMENT: - comment = line.Value; - break; - case TAG_DISC: - int tryDisc; - if (int.TryParse(line.Value, out tryDisc)) - disc = tryDisc; - break; - case TAG_POS: - int tryPos; - if (int.TryParse(line.Value, out tryPos)) - pos = tryPos; - break; - case TAG_ID: - int tryId; - if (int.TryParse(line.Value, out tryId)) - id = tryId; - break; - } - } - - if (file != null) - ret.Add(new MpdFile( - file, - time, - album, - artist, - title, - track, - name, - genre, - date, - composer, - performer, - comment, - disc, - pos, - id )); - - return ret; - } - */ - } -} diff --git a/LibMpc/MpdOutput.cs b/LibMpc/MpdOutput.cs deleted file mode 100644 index 5420451..0000000 --- a/LibMpc/MpdOutput.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; - -namespace LibMpc -{ - /// - /// The MpdOutput class contains all attributes of an output device of the MPD. - /// - public class MpdOutput - { - private readonly int id; - private readonly string name; - private readonly bool enabled; - /// - /// The id of the output. - /// - public int Id { get { return this.id; } } - /// - /// The name of the output. - /// - public string Name { get { return this.name; } } - /// - /// If the output is enabled. - /// - public bool IsEnabled { get { return this.enabled; } } - /// - /// Creates a new MpdOutput object. - /// - /// The id of the output. - /// The name of the output. - /// If the output is enabled. - public MpdOutput(int id, string name, bool enabled) - { - if (name == null) - throw new ArgumentNullException("name"); - - this.id = id; - this.name = name; - this.enabled = enabled; - } - /// - /// Returns a string representation of the object mainly for debuging purpose. - /// - /// A string representation of the object. - public override string ToString() - { - return this.id + "::" + this.name + "::" + this.enabled; - } - } -} diff --git a/LibMpc/Types/MpdDirectory.cs b/LibMpc/Types/MpdDirectory.cs new file mode 100644 index 0000000..f71e2a9 --- /dev/null +++ b/LibMpc/Types/MpdDirectory.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using System.Linq; + +namespace LibMpc.Types +{ + public class MpdDirectory + { + private readonly IList _files = new List(); + private readonly IList _subDirectories = new List(); + + public MpdDirectory(string path) + { + path.CheckNotNull(); + + Path = path; + + var name = path.Split('/').Last(); + Name = string.IsNullOrEmpty(name) ? "root" : name; + } + + public string Path { get; } + public string Name { get; } + public IEnumerable Files => _files; + public IEnumerable SubDirectories => _subDirectories; + + internal void AddFile(string file) + { + var filePath = file.Split('/'); + var name = filePath[filePath.Length - 1]; + + if (filePath.Length == 1) + { + _files.Add(new MpdFile(name)); + } + else + { + var filePathWithoutCurrentDirectory = string.Join("/", filePath.Skip(1)); + foreach (var subDirectory in _subDirectories) + { + if (subDirectory.Path.Equals(filePath[0])) + { + subDirectory.AddFile(filePathWithoutCurrentDirectory); + } + } + } + } + + internal void AddDirectory(string directory) + { + var directoryPath = directory.Split('/'); + var name = directoryPath[directoryPath.Length - 1]; + + if (directoryPath.Length == 1) + { + _subDirectories.Add(new MpdDirectory(name)); + } + else + { + var directoryPathWithoutCurrentDirectory = string.Join("/", directoryPath.Skip(1)); + foreach (var subDirectory in _subDirectories) + { + if (subDirectory.Path.Equals(directoryPath[0])) + { + subDirectory.AddDirectory(directoryPathWithoutCurrentDirectory); + } + } + } + } + } +} \ No newline at end of file diff --git a/LibMpc/Types/MpdFile.cs b/LibMpc/Types/MpdFile.cs new file mode 100644 index 0000000..204b828 --- /dev/null +++ b/LibMpc/Types/MpdFile.cs @@ -0,0 +1,73 @@ +namespace LibMpc.Types +{ + public class MpdFileBuidler + { + private const string TagFile = "file"; + private const string TagTime = "Time"; + private const string TagArtist = "Artist"; + private const string TagAlbum = "Album"; + private const string TagTitle = "Title"; + private const string TagTrack = "Track"; + private const string TagName = "Name"; + private const string TagGenre = "Genre"; + private const string TagDate = "Date"; + private const string TagComposer = "Composer"; + private const string TagPerformer = "Performer"; + private const string TagComment = "Comment"; + private const string TagDisc = "Disc"; + private const string TagPos = "Pos"; + private const string TagId = "Id"; + + private MpdFile _mpdFile; + + public bool IsInitialized => _mpdFile != null; + + public MpdFileBuidler Init(string file) + { + _mpdFile = new MpdFile(file); + return this; + } + + public MpdFileBuidler WithProperty(string tag, string value) + { + _mpdFile.CheckNotNull(); + + // TODO: Parse tag + + return this; + } + + public MpdFile Build() + { + return _mpdFile; + } + } + + + /// + /// The MpdFile class contains all meta data for a file of the MPD. + /// + public class MpdFile + { + public MpdFile(string file) + { + File = file; + } + + public string File { get; } + public int Time { get; internal set; } = -1; + public string Album { get; internal set; } = string.Empty; + public string Artist { get; internal set; } = string.Empty; + public string Title { get; internal set; } = string.Empty; + public string Track { get; internal set; } = string.Empty; + public string Name { get; internal set; } = string.Empty; + public string Genre { get; internal set; } = string.Empty; + public string Date { get; internal set; } = string.Empty; + public string Composer { get; internal set; } = string.Empty; + public string Performer { get; internal set; } = string.Empty; + public string Comment { get; internal set; } = string.Empty; + public int Disc { get; internal set; } = -1; + public int Pos { get; internal set; } = -1; + public int Id { get; internal set; } = -1; + } +} diff --git a/LibMpc/Types/MpdOutput.cs b/LibMpc/Types/MpdOutput.cs new file mode 100644 index 0000000..5eaeba1 --- /dev/null +++ b/LibMpc/Types/MpdOutput.cs @@ -0,0 +1,21 @@ +namespace LibMpc.Types +{ + /// + /// The MpdOutput class contains all attributes of an output device of the MPD. + /// + public class MpdOutput + { + public MpdOutput(int id, string name, bool enabled) + { + name.CheckNotNull(); + + Id = id; + Name = name; + IsEnabled = enabled; + } + + public int Id { get; } + public string Name { get; } + public bool IsEnabled { get; } + } +} \ No newline at end of file diff --git a/LibMpcTest/LibMpcTest.cs b/LibMpcTest/LibMpcTest.cs index ace1279..ee4408e 100644 --- a/LibMpcTest/LibMpcTest.cs +++ b/LibMpcTest/LibMpcTest.cs @@ -1,5 +1,6 @@ using LibMpc; using System; +using System.Diagnostics; using System.Linq; using System.Net; using System.Threading.Tasks; @@ -25,11 +26,11 @@ namespace LibMpcTest var connected = Task.Run(async () => await _mpc.ConnectAsync()).Result; if (connected) { - Console.Out.WriteLine("Connected to MPD."); + WriteLine("Connected to MPD."); } else { - Console.Out.WriteLine("Could not connect to MPD."); + WriteLine("Could not connect to MPD."); } } @@ -38,11 +39,10 @@ namespace LibMpcTest { var response = await _mpc.SendAsync(new Commands.Reflection.TagTypes()); - Console.Out.WriteLine("TagTypesTest Result:"); - Console.Out.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + WriteLine("TagTypesTest Result:"); + WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); - Assert.True(response.Response.Body.Keys.Contains("tagtypes")); - Assert.True(response.Response.Body.Values.Any()); + Assert.True(response.Response.Body.Count().Equals(17)); } [Fact] @@ -50,16 +50,25 @@ namespace LibMpcTest { var response = await _mpc.SendAsync(new Commands.Database.ListAll()); - Console.Out.WriteLine("ListAllTest Result:"); - Console.Out.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + WriteLine("ListAllTest Result:"); + WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); - Assert.True(response.Response.Body.Keys.Contains("directories")); - Assert.True(response.Response.Body["directories"].Count.Equals(5)); + Assert.True(response.Response.Body.SubDirectories.Count().Equals(4)); + Assert.True(response.Response.Body.Files.Count().Equals(3)); } public void Dispose() { _mpc?.DisconnectAsync().GetAwaiter().GetResult(); } + + private void WriteLine(string value) + { +#if DEBUG + Debug.WriteLine(value); +#else + Console.Out.WriteLine(value); +#endif + } } } diff --git a/LibMpcTest/Server/Music/A long name directory with some spaces/short-trouser-pants-zip-closing.mp3 b/LibMpcTest/Server/Music/A long name directory with some spaces/Sub Directory Two/short-trouser-pants-zip-closing.mp3 similarity index 100% rename from LibMpcTest/Server/Music/A long name directory with some spaces/short-trouser-pants-zip-closing.mp3 rename to LibMpcTest/Server/Music/A long name directory with some spaces/Sub Directory Two/short-trouser-pants-zip-closing.mp3 diff --git a/LibMpcTest/Server/Music/A long name directory with some spaces/starting-engine-Ford-Mondeo-Mk-3-diesel.mp3 b/LibMpcTest/Server/Music/A long name directory with some spaces/Sub Directory Two/starting-engine-Ford-Mondeo-Mk-3-diesel.mp3 similarity index 100% rename from LibMpcTest/Server/Music/A long name directory with some spaces/starting-engine-Ford-Mondeo-Mk-3-diesel.mp3 rename to LibMpcTest/Server/Music/A long name directory with some spaces/Sub Directory Two/starting-engine-Ford-Mondeo-Mk-3-diesel.mp3 diff --git a/LibMpcTest/Server/Music/Directory With Spaces/central-locking-Ford-Mondeo-Mk-3.mp3 b/LibMpcTest/Server/Music/Directory With Spaces/SubDirectory One/central-locking-Ford-Mondeo-Mk-3.mp3 similarity index 100% rename from LibMpcTest/Server/Music/Directory With Spaces/central-locking-Ford-Mondeo-Mk-3.mp3 rename to LibMpcTest/Server/Music/Directory With Spaces/SubDirectory One/central-locking-Ford-Mondeo-Mk-3.mp3 diff --git a/LibMpcTest/Server/mpd.db b/LibMpcTest/Server/mpd.db index c1f0c92..021cf41 100644 --- a/LibMpcTest/Server/mpd.db +++ b/LibMpcTest/Server/mpd.db @@ -21,23 +21,36 @@ tag: MUSICBRAINZ_ALBUMARTISTID tag: MUSICBRAINZ_TRACKID info_end directory: A long name directory with some spaces -mtime: 1481622608 +mtime: 1482142041 begin: A long name directory with some spaces -song_begin: pouring-water-into-mug-of-coffee.mp3 -Time: 4 -Artist: Geek & Dummy -Title: Sound effect: pouring water into mug of coffee -Date: 2013 -Date: 2013 -mtime: 1481622059 -song_end +directory: Sub Directory Two +mtime: 1482142041 +begin: A long name directory with some spaces/Sub Directory Two song_begin: short-trouser-pants-zip-closing.mp3 Time: 1 Artist: Geek & Dummy Title: Sound effect: short trouser pants zip closing Date: 2013 Date: 2013 -mtime: 1481622066 +mtime: 1481623577 +song_end +song_begin: starting-engine-Ford-Mondeo-Mk-3-diesel.mp3 +Time: 6 +Artist: Geek & Dummy +Title: Sound effect: starting engine - Ford Mondeo Mk 3 diesel +Album: Geek & Dummy Sound Library +Date: 2014 +Genre: soundfx +mtime: 1481623577 +song_end +end: A long name directory with some spaces/Sub Directory Two +song_begin: pouring-water-into-mug-of-coffee.mp3 +Time: 4 +Artist: Geek & Dummy +Title: Sound effect: pouring water into mug of coffee +Date: 2013 +Date: 2013 +mtime: 1481623577 song_end song_begin: Ghost-Sounds.mp3 Time: 95 @@ -47,20 +60,11 @@ Album: Geek & Dummy Sound Library Date: 2014 Date: 2014 Genre: soundfx -mtime: 1481622054 -song_end -song_begin: starting-engine-Ford-Mondeo-Mk-3-diesel.mp3 -Time: 6 -Artist: Geek & Dummy -Title: Sound effect: starting engine - Ford Mondeo Mk 3 diesel -Album: Geek & Dummy Sound Library -Date: 2014 -Genre: soundfx -mtime: 1481622063 +mtime: 1481623577 song_end end: A long name directory with some spaces directory: Directory -mtime: 1481622608 +mtime: 1482142041 begin: Directory song_begin: 2-Kids-Laughing.mp3 Time: 30 @@ -70,7 +74,7 @@ Album: Geek & Dummy Sound Library Date: 2014 Date: 2014 Genre: soundfx -mtime: 1481622083 +mtime: 1481623577 song_end song_begin: ambient-noise-server-room.mp3 Time: 71 @@ -80,20 +84,15 @@ Album: Geek & Dummy Sound Library Date: 2014 Date: 2014 Genre: soundfx -mtime: 1481622020 +mtime: 1481623577 song_end end: Directory directory: Directory With Spaces -mtime: 1481622608 +mtime: 1482142041 begin: Directory With Spaces -song_begin: coin-spin-light.mp3 -Time: 5 -Artist: Geek & Dummy -Title: Sound effect: coin spin (light coin) -Date: 2013 -Date: 2013 -mtime: 1481622036 -song_end +directory: SubDirectory One +mtime: 1482142041 +begin: Directory With Spaces/SubDirectory One song_begin: central-locking-Ford-Mondeo-Mk-3.mp3 Time: 5 Artist: Geek & Dummy @@ -102,7 +101,16 @@ Album: Geek & Dummy Sound Library Date: 2014 Date: 2014 Genre: soundfx -mtime: 1481622024 +mtime: 1481623577 +song_end +end: Directory With Spaces/SubDirectory One +song_begin: coin-spin-light.mp3 +Time: 5 +Artist: Geek & Dummy +Title: Sound effect: coin spin (light coin) +Date: 2013 +Date: 2013 +mtime: 1481623577 song_end song_begin: finger-snap-click.mp3 Time: 0 @@ -112,11 +120,11 @@ Album: Geek & Dummy Sound Library Date: 2014 Date: 2014 Genre: soundfx -mtime: 1481622047 +mtime: 1481623577 song_end end: Directory With Spaces directory: _My Directory -mtime: 1481622608 +mtime: 1482142041 begin: _My Directory song_begin: gas-fire-lighting.mp3 Time: 58 @@ -126,7 +134,7 @@ Album: Geek & Dummy Sound Library Date: 2014 Date: 2014 Genre: soundfx -mtime: 1481622051 +mtime: 1481623577 song_end end: _My Directory song_begin: teaspoon-stirring-mug-of-coffee.mp3 @@ -135,7 +143,7 @@ Artist: Geek & Dummy Title: Sound effect: teaspoon stirring mug of coffee Date: 2013 Date: 2013 -mtime: 1481622029 +mtime: 1481623577 song_end song_begin: whistle-kettle-boiling.mp3 Time: 36 @@ -143,7 +151,7 @@ Artist: Geek & Dummy Title: Sound effect: whistle kettle boiling Date: 2013 Date: 2013 -mtime: 1481622087 +mtime: 1481623577 song_end song_begin: wine-glass-double-chink-clink-cheers.mp3 Time: 1 @@ -151,5 +159,5 @@ Artist: Geek & Dummy Title: Sound effect: wine glass double chink/clink/cheers Date: 2013 Date: 2013 -mtime: 1481622090 +mtime: 1481623577 song_end From 01b928f29eadbe769d4c0d938fe20acc6668a8f6 Mon Sep 17 00:00:00 2001 From: glucaci Date: Mon, 19 Dec 2016 12:12:58 +0100 Subject: [PATCH 02/24] Fix build --- LibMpc/MpdDirectoryListing.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/LibMpc/MpdDirectoryListing.cs b/LibMpc/MpdDirectoryListing.cs index 04e6a82..cb8b3f9 100644 --- a/LibMpc/MpdDirectoryListing.cs +++ b/LibMpc/MpdDirectoryListing.cs @@ -1,6 +1,7 @@ using System; using System.Collections.ObjectModel; using System.Collections.Generic; +using LibMpc.Types; namespace LibMpc { From 7068ac9db04dff5ba97cc58cf3f3710db2688538 Mon Sep 17 00:00:00 2001 From: glucaci Date: Mon, 19 Dec 2016 16:29:58 +0100 Subject: [PATCH 03/24] Test for Find command. MpdDirectory and MpdFile few changes. --- LibMpc/Commands/Commands.Database.cs | 25 +++--- LibMpc/Types/MpdDirectory.cs | 43 +-------- LibMpc/Types/MpdFile.cs | 127 +++++++++++++++++---------- LibMpcTest/LibMpcTest.cs | 18 ++-- 4 files changed, 107 insertions(+), 106 deletions(-) diff --git a/LibMpc/Commands/Commands.Database.cs b/LibMpc/Commands/Commands.Database.cs index 1db9e4d..fe9eb31 100644 --- a/LibMpc/Commands/Commands.Database.cs +++ b/LibMpc/Commands/Commands.Database.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using LibMpc.Types; namespace LibMpc @@ -29,21 +30,21 @@ namespace LibMpc { var results = new List(); - var fileBuilder = new MpdFileBuidler(); + var mpdFile = MpdFile.EmptyFile; foreach (var line in response) { if (line.Key.Equals("file")) { - if (fileBuilder.IsInitialized) + if (mpdFile.IsInitialized) { - results.Add(fileBuilder.Build()); + results.Add(mpdFile); } - fileBuilder.Init(line.Value); + mpdFile = new MpdFile(line.Value); } else { - fileBuilder.WithProperty(line.Key, line.Value); + mpdFile.AddTag(line.Key, line.Value); } } @@ -71,25 +72,27 @@ namespace LibMpc // TODO: findadd - public class ListAll : IMpcCommand + public class ListAll : IMpcCommand> { public string Value => "listall"; - public MpdDirectory FormatResponse(IList> response) + public IEnumerable FormatResponse(IList> response) { - // Add by default the root directory - var rootDirectory = new MpdDirectory("/"); + var rootDirectory = new List + { + new MpdDirectory("/") // Add by default the root directory + }; foreach (var line in response) { if (line.Key.Equals("file")) { - rootDirectory.AddFile(line.Value); + rootDirectory.Last().AddFile(line.Value); } if (line.Key.Equals("directory")) { - rootDirectory.AddDirectory(line.Value); + rootDirectory.Add(new MpdDirectory(line.Value)); } } diff --git a/LibMpc/Types/MpdDirectory.cs b/LibMpc/Types/MpdDirectory.cs index f71e2a9..561288f 100644 --- a/LibMpc/Types/MpdDirectory.cs +++ b/LibMpc/Types/MpdDirectory.cs @@ -6,7 +6,6 @@ namespace LibMpc.Types public class MpdDirectory { private readonly IList _files = new List(); - private readonly IList _subDirectories = new List(); public MpdDirectory(string path) { @@ -21,50 +20,10 @@ namespace LibMpc.Types public string Path { get; } public string Name { get; } public IEnumerable Files => _files; - public IEnumerable SubDirectories => _subDirectories; internal void AddFile(string file) { - var filePath = file.Split('/'); - var name = filePath[filePath.Length - 1]; - - if (filePath.Length == 1) - { - _files.Add(new MpdFile(name)); - } - else - { - var filePathWithoutCurrentDirectory = string.Join("/", filePath.Skip(1)); - foreach (var subDirectory in _subDirectories) - { - if (subDirectory.Path.Equals(filePath[0])) - { - subDirectory.AddFile(filePathWithoutCurrentDirectory); - } - } - } - } - - internal void AddDirectory(string directory) - { - var directoryPath = directory.Split('/'); - var name = directoryPath[directoryPath.Length - 1]; - - if (directoryPath.Length == 1) - { - _subDirectories.Add(new MpdDirectory(name)); - } - else - { - var directoryPathWithoutCurrentDirectory = string.Join("/", directoryPath.Skip(1)); - foreach (var subDirectory in _subDirectories) - { - if (subDirectory.Path.Equals(directoryPath[0])) - { - subDirectory.AddDirectory(directoryPathWithoutCurrentDirectory); - } - } - } + _files.Add(new MpdFile(file)); } } } \ No newline at end of file diff --git a/LibMpc/Types/MpdFile.cs b/LibMpc/Types/MpdFile.cs index 204b828..12a15c3 100644 --- a/LibMpc/Types/MpdFile.cs +++ b/LibMpc/Types/MpdFile.cs @@ -1,8 +1,14 @@ -namespace LibMpc.Types +using System.Collections.Generic; + +namespace LibMpc.Types { - public class MpdFileBuidler + /// + /// The MpdFile class contains all meta data for a file of the MPD. + /// + public class MpdFile { - private const string TagFile = "file"; + public static readonly MpdFile EmptyFile = new MpdFile(string.Empty); + private const string TagTime = "Time"; private const string TagArtist = "Artist"; private const string TagAlbum = "Album"; @@ -18,56 +24,83 @@ private const string TagPos = "Pos"; private const string TagId = "Id"; - private MpdFile _mpdFile; + private readonly IDictionary _unknownTags = new Dictionary(); - public bool IsInitialized => _mpdFile != null; - - public MpdFileBuidler Init(string file) - { - _mpdFile = new MpdFile(file); - return this; - } - - public MpdFileBuidler WithProperty(string tag, string value) - { - _mpdFile.CheckNotNull(); - - // TODO: Parse tag - - return this; - } - - public MpdFile Build() - { - return _mpdFile; - } - } - - - /// - /// The MpdFile class contains all meta data for a file of the MPD. - /// - public class MpdFile - { public MpdFile(string file) { File = file; + IsInitialized = !string.IsNullOrEmpty(File); } public string File { get; } - public int Time { get; internal set; } = -1; - public string Album { get; internal set; } = string.Empty; - public string Artist { get; internal set; } = string.Empty; - public string Title { get; internal set; } = string.Empty; - public string Track { get; internal set; } = string.Empty; - public string Name { get; internal set; } = string.Empty; - public string Genre { get; internal set; } = string.Empty; - public string Date { get; internal set; } = string.Empty; - public string Composer { get; internal set; } = string.Empty; - public string Performer { get; internal set; } = string.Empty; - public string Comment { get; internal set; } = string.Empty; - public int Disc { get; internal set; } = -1; - public int Pos { get; internal set; } = -1; - public int Id { get; internal set; } = -1; + public int Time { get; private set; } = -1; + public string Album { get; private set; } = string.Empty; + public string Artist { get; private set; } = string.Empty; + public string Title { get; private set; } = string.Empty; + public string Track { get; private set; } = string.Empty; + public string Name { get; private set; } = string.Empty; + public string Genre { get; private set; } = string.Empty; + public string Date { get; private set; } = string.Empty; + public string Composer { get; private set; } = string.Empty; + public string Performer { get; private set; } = string.Empty; + public string Comment { get; private set; } = string.Empty; + public int Disc { get; private set; } = -1; + public int Pos { get; private set; } = -1; + public int Id { get; private set; } = -1; + public IDictionary UnknownTags => _unknownTags; + + internal bool IsInitialized { get; } + + internal void AddTag(string tag, string value) + { + switch (tag) + { + case TagTime: + Time = int.Parse(value); + break; + case TagArtist: + Artist = value; + break; + case TagAlbum: + Album = value; + break; + case TagTitle: + Title = value; + break; + case TagTrack: + Track = value; + break; + case TagName: + Name = value; + break; + case TagGenre: + Genre = value; + break; + case TagDate: + Date = value; + break; + case TagComposer: + Composer = value; + break; + case TagPerformer: + Performer = value; + break; + case TagComment: + Comment = value; + break; + case TagDisc: + Disc = int.Parse(value); + break; + case TagPos: + Pos = int.Parse(value); + break; + case TagId: + Id = int.Parse(value); + break; + default: + _unknownTags.Add(tag, value); + break; + } + } } } diff --git a/LibMpcTest/LibMpcTest.cs b/LibMpcTest/LibMpcTest.cs index ee4408e..4a2332d 100644 --- a/LibMpcTest/LibMpcTest.cs +++ b/LibMpcTest/LibMpcTest.cs @@ -53,8 +53,18 @@ namespace LibMpcTest WriteLine("ListAllTest Result:"); WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); - Assert.True(response.Response.Body.SubDirectories.Count().Equals(4)); - Assert.True(response.Response.Body.Files.Count().Equals(3)); + Assert.True(response.Response.Body.Count().Equals(7)); + } + + [Fact] + public async Task FindGenreTest() + { + var response = await _mpc.SendAsync(new Commands.Database.Find(MpdTags.Genre, "soundfx")); + + WriteLine("FindGenreTest Result:"); + WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Count().Equals(6)); } public void Dispose() @@ -64,11 +74,7 @@ namespace LibMpcTest private void WriteLine(string value) { -#if DEBUG - Debug.WriteLine(value); -#else Console.Out.WriteLine(value); -#endif } } } From fe55423be2853759cf9be908c102e2a3e1acd029 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 10:42:53 +0100 Subject: [PATCH 04/24] Send only single command to MPD. --- LibMpc/Mpc.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/LibMpc/Mpc.cs b/LibMpc/Mpc.cs index 664f75d..1a23a04 100644 --- a/LibMpc/Mpc.cs +++ b/LibMpc/Mpc.cs @@ -1,7 +1,7 @@ -using System; using System.Collections.Generic; using System.Net; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; namespace LibMpc @@ -14,6 +14,7 @@ namespace LibMpc { private static readonly Regex STATUS_AUDIO_REGEX = new Regex("^(?[0-9]*):(?[0-9]*):(?[0-9]*)$"); + private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly IPEndPoint _server; private MpcConnection _connection; @@ -54,9 +55,15 @@ namespace LibMpc public async Task> SendAsync(IMpcCommand command) { - var mpdMessage = await _connection.SendAsync(command); - - return mpdMessage; + await _semaphore.WaitAsync(); + try + { + return await _connection.SendAsync(command); + } + finally + { + _semaphore.Release(); + } } /* From 8c3dbecd71669d63dd87841a02ee9008f96921b3 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 10:44:56 +0100 Subject: [PATCH 05/24] Multiple audio configuration for MockServer --- LibMpcTest/MpdConf.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/LibMpcTest/MpdConf.cs b/LibMpcTest/MpdConf.cs index d44b399..0570f42 100644 --- a/LibMpcTest/MpdConf.cs +++ b/LibMpcTest/MpdConf.cs @@ -28,7 +28,20 @@ namespace LibMpcTest builder.AppendLine("port \"6600\""); builder.AppendLine("audio_output {"); builder.AppendLine("type \"null\""); - builder.AppendLine("name \"No Output\""); + builder.AppendLine("name \"Output One\""); + builder.AppendLine("enabled \"true\""); + builder.AppendLine("mixer_type \"none\""); + builder.AppendLine("}"); + builder.AppendLine("audio_output {"); + builder.AppendLine("type \"null\""); + builder.AppendLine("name \"Output Two\""); + builder.AppendLine("enabled \"false\""); + builder.AppendLine("mixer_type \"none\""); + builder.AppendLine("}"); + builder.AppendLine("audio_output {"); + builder.AppendLine("type \"null\""); + builder.AppendLine("name \"Output Three\""); + builder.AppendLine("enabled \"true\""); builder.AppendLine("mixer_type \"none\""); builder.AppendLine("}"); From 918dc5141a711f3a3a143fc0cd4423f9ccdcd254 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 10:46:40 +0100 Subject: [PATCH 06/24] Use only one Client and one Server for all Tests. Output tests. --- LibMpc/Commands/Commands.Output.cs | 10 +-- LibMpcTest/LibMpcTest.cs | 76 +++------------------ LibMpcTest/MpcMock.cs | 26 +++++++ LibMpcTest/{MpdServerTest.cs => MpdMock.cs} | 17 ++--- LibMpcTest/Tests/DatabaseCommandsTest.cs | 33 +++++++++ LibMpcTest/Tests/OutputCommandsTest.cs | 59 ++++++++++++++++ LibMpcTest/Tests/ReflectionCommandsTest.cs | 22 ++++++ 7 files changed, 164 insertions(+), 79 deletions(-) create mode 100644 LibMpcTest/MpcMock.cs rename LibMpcTest/{MpdServerTest.cs => MpdMock.cs} (82%) create mode 100644 LibMpcTest/Tests/DatabaseCommandsTest.cs create mode 100644 LibMpcTest/Tests/OutputCommandsTest.cs create mode 100644 LibMpcTest/Tests/ReflectionCommandsTest.cs diff --git a/LibMpc/Commands/Commands.Output.cs b/LibMpc/Commands/Commands.Output.cs index 3c76ea1..54725ef 100644 --- a/LibMpc/Commands/Commands.Output.cs +++ b/LibMpc/Commands/Commands.Output.cs @@ -26,8 +26,8 @@ namespace LibMpc public string FormatResponse(IList> response) { - // TODO: - return response.ToString(); + // Response should be empty. + return string.Join(", ", response); } } @@ -47,8 +47,8 @@ namespace LibMpc public string FormatResponse(IList> response) { - // TODO: - return response.ToString(); + // Response should be empty. + return string.Join(", ", response); } } @@ -69,7 +69,7 @@ namespace LibMpc { var outputId = int.Parse(response[i].Value); var outputName = response[i + 1].Value; - var outputEnabled = bool.Parse(response[i + 2].Value); + var outputEnabled = response[i + 2].Value == "1"; result.Add(new MpdOutput(outputId, outputName, outputEnabled)); } diff --git a/LibMpcTest/LibMpcTest.cs b/LibMpcTest/LibMpcTest.cs index 4a2332d..bb77415 100644 --- a/LibMpcTest/LibMpcTest.cs +++ b/LibMpcTest/LibMpcTest.cs @@ -1,80 +1,24 @@ using LibMpc; -using System; using System.Diagnostics; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Newtonsoft.Json; using Xunit; -using Xunit.Abstractions; namespace LibMpcTest { - public class LibMpcTest : IClassFixture, IDisposable + public partial class LibMpcTest : IClassFixture, IClassFixture { - private readonly MpdServerTest _server; - private readonly ITestOutputHelper _output; - private readonly Mpc _mpc; - - public LibMpcTest(MpdServerTest server, ITestOutputHelper output) + public LibMpcTest(MpcMock mpc) { - _server = server; - _output = output; - - _mpc = new Mpc(new IPEndPoint(IPAddress.Loopback, 6600)); - - var connected = Task.Run(async () => await _mpc.ConnectAsync()).Result; - if (connected) - { - WriteLine("Connected to MPD."); - } - else - { - WriteLine("Could not connect to MPD."); - } + Mpc = mpc.Client; } - [Fact] - public async Task TagTypesTest() + internal Mpc Mpc { get; } + } + + internal class TestUtils + { + internal static void WriteLine(string value) { - var response = await _mpc.SendAsync(new Commands.Reflection.TagTypes()); - - WriteLine("TagTypesTest Result:"); - WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); - - Assert.True(response.Response.Body.Count().Equals(17)); - } - - [Fact] - public async Task ListAllTest() - { - var response = await _mpc.SendAsync(new Commands.Database.ListAll()); - - WriteLine("ListAllTest Result:"); - WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); - - Assert.True(response.Response.Body.Count().Equals(7)); - } - - [Fact] - public async Task FindGenreTest() - { - var response = await _mpc.SendAsync(new Commands.Database.Find(MpdTags.Genre, "soundfx")); - - WriteLine("FindGenreTest Result:"); - WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); - - Assert.True(response.Response.Body.Count().Equals(6)); - } - - public void Dispose() - { - _mpc?.DisconnectAsync().GetAwaiter().GetResult(); - } - - private void WriteLine(string value) - { - Console.Out.WriteLine(value); + Debug.WriteLine(value); } } } diff --git a/LibMpcTest/MpcMock.cs b/LibMpcTest/MpcMock.cs new file mode 100644 index 0000000..f75264d --- /dev/null +++ b/LibMpcTest/MpcMock.cs @@ -0,0 +1,26 @@ +using LibMpc; +using System; +using System.Net; +using System.Threading.Tasks; + +namespace LibMpcTest +{ + public class MpcMock : IDisposable + { + public MpcMock() + { + Client = new Mpc(new IPEndPoint(IPAddress.Loopback, 6600)); + + var connected = Task.Run(async () => await Client.ConnectAsync()).Result; + TestUtils.WriteLine($"Connected to MPD : {connected}"); + } + + public Mpc Client { get; } + + public void Dispose() + { + Client?.DisconnectAsync().GetAwaiter().GetResult(); + TestUtils.WriteLine($"Disconnected from MPD."); + } + } +} \ No newline at end of file diff --git a/LibMpcTest/MpdServerTest.cs b/LibMpcTest/MpdMock.cs similarity index 82% rename from LibMpcTest/MpdServerTest.cs rename to LibMpcTest/MpdMock.cs index d3f9b2d..e0935dd 100644 --- a/LibMpcTest/MpdServerTest.cs +++ b/LibMpcTest/MpdMock.cs @@ -5,9 +5,9 @@ using System.Runtime.InteropServices; namespace LibMpcTest { - public class MpdServerTest : IDisposable + public class MpdMock : IDisposable { - public MpdServerTest() + public MpdMock() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { @@ -32,11 +32,11 @@ namespace LibMpcTest } }; - Console.Out.WriteLine($"Starting Server: {Process.StartInfo.FileName} {Process.StartInfo.Arguments}"); + TestUtils.WriteLine($"Starting Server: {Process.StartInfo.FileName} {Process.StartInfo.Arguments}"); Process.Start(); - Console.Out.WriteLine($"Output: {Process.StandardOutput.ReadToEnd()}"); - Console.Out.WriteLine($"Error: {Process.StandardError.ReadToEnd()}"); + TestUtils.WriteLine($"Output: {Process.StandardOutput.ReadToEnd()}"); + TestUtils.WriteLine($"Error: {Process.StandardError.ReadToEnd()}"); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { @@ -80,15 +80,16 @@ namespace LibMpcTest netcat.Start(); netcat.WaitForExit(); - Console.Out.WriteLine(command); - Console.Out.WriteLine($"Output: {netcat.StandardOutput.ReadToEnd()}"); - Console.Out.WriteLine($"Error: {netcat.StandardError.ReadToEnd()}"); + TestUtils.WriteLine(command); + TestUtils.WriteLine($"Output: {netcat.StandardOutput.ReadToEnd()}"); + TestUtils.WriteLine($"Error: {netcat.StandardError.ReadToEnd()}"); } public void Dispose() { Process?.Kill(); Process?.Dispose(); + TestUtils.WriteLine("Server Stopped."); } private class Server diff --git a/LibMpcTest/Tests/DatabaseCommandsTest.cs b/LibMpcTest/Tests/DatabaseCommandsTest.cs new file mode 100644 index 0000000..16b28b8 --- /dev/null +++ b/LibMpcTest/Tests/DatabaseCommandsTest.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using Newtonsoft.Json; +using Xunit; +using System.Linq; +using LibMpc; + +namespace LibMpcTest +{ + public partial class LibMpcTest + { + [Fact] + public async Task ListAllTest() + { + var response = await Mpc.SendAsync(new Commands.Database.ListAll()); + + TestUtils.WriteLine("ListAllTest Result:"); + TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Count().Equals(7)); + } + + [Fact] + public async Task FindGenreTest() + { + var response = await Mpc.SendAsync(new Commands.Database.Find(MpdTags.Genre, "soundfx")); + + TestUtils.WriteLine("FindGenreTest Result:"); + TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Count().Equals(6)); + } + } +} \ No newline at end of file diff --git a/LibMpcTest/Tests/OutputCommandsTest.cs b/LibMpcTest/Tests/OutputCommandsTest.cs new file mode 100644 index 0000000..c46a35b --- /dev/null +++ b/LibMpcTest/Tests/OutputCommandsTest.cs @@ -0,0 +1,59 @@ +using System.Threading.Tasks; +using Newtonsoft.Json; +using Xunit; +using LibMpc; +using System.Linq; + +namespace LibMpcTest +{ + public partial class LibMpcTest + { + [Fact] + public async Task DisableOutputTest() + { + var responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs()); + Assert.True(responseOutputs.Response.Body.Single(output => output.Id.Equals(2)).IsEnabled); + + var response = await Mpc.SendAsync(new Commands.Output.DisableOutput(2)); + + TestUtils.WriteLine("DisableOutputTest Result:"); + TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Equals(string.Empty)); + Assert.True(response.Response.State.Status.Equals("OK")); + + responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs()); + Assert.False(responseOutputs.Response.Body.Single(output => output.Id.Equals(2)).IsEnabled); + } + + [Fact] + public async Task EnableOutputTest() + { + var responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs()); + // By default should be disable from mpd.config + Assert.False(responseOutputs.Response.Body.Single(output => output.Id.Equals(1)).IsEnabled); + + var response = await Mpc.SendAsync(new Commands.Output.EnableOutput(1)); + + TestUtils.WriteLine("EnableOutputTest Result:"); + TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Equals(string.Empty)); + Assert.True(response.Response.State.Status.Equals("OK")); + + responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs()); + Assert.True(responseOutputs.Response.Body.Single(output => output.Id.Equals(1)).IsEnabled); + } + + [Fact] + public async Task LisOutputsTest() + { + var response = await Mpc.SendAsync(new Commands.Output.Outputs()); + + TestUtils.WriteLine("LisOutputsTest Result:"); + TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Count().Equals(3)); + } + } +} \ No newline at end of file diff --git a/LibMpcTest/Tests/ReflectionCommandsTest.cs b/LibMpcTest/Tests/ReflectionCommandsTest.cs new file mode 100644 index 0000000..4067373 --- /dev/null +++ b/LibMpcTest/Tests/ReflectionCommandsTest.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Newtonsoft.Json; +using Xunit; +using LibMpc; +using System.Linq; + +namespace LibMpcTest +{ + public partial class LibMpcTest + { + [Fact] + public async Task TagTypesTest() + { + var response = await Mpc.SendAsync(new Commands.Reflection.TagTypes()); + + TestUtils.WriteLine("TagTypesTest Result:"); + TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Count().Equals(17)); + } + } +} \ No newline at end of file From 9885ffa87bfde1185b4fa950dc4d3e509612f469 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 10:50:13 +0100 Subject: [PATCH 07/24] ConsoleApp removed => Unit Test instead. --- LibMpc.sln | 6 -- LibMpcApp/LibMpcApp.xproj | 21 ------- LibMpcApp/Program.cs | 88 ---------------------------- LibMpcApp/Properties/AssemblyInfo.cs | 19 ------ LibMpcApp/project.json | 20 ------- 5 files changed, 154 deletions(-) delete mode 100644 LibMpcApp/LibMpcApp.xproj delete mode 100644 LibMpcApp/Program.cs delete mode 100644 LibMpcApp/Properties/AssemblyInfo.cs delete mode 100644 LibMpcApp/project.json diff --git a/LibMpc.sln b/LibMpc.sln index 6f7d4f0..f7f72df 100644 --- a/LibMpc.sln +++ b/LibMpc.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "LibMpc", "LibMpc\LibMpc.xproj", "{8994C820-7BA9-4BB8-B9EA-C608B07C4A11}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "LibMpcApp", "LibMpcApp\LibMpcApp.xproj", "{FF176AD5-D6DA-41EE-B27D-1DBEF0CE462F}" -EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "LibMpcTest", "LibMpcTest\LibMpcTest.xproj", "{69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Utilities", "Solution Utilities", "{83D06F7C-1336-4AC3-82BB-FDE7940D3C10}" @@ -24,10 +22,6 @@ Global {8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Debug|Any CPU.Build.0 = Debug|Any CPU {8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|Any CPU.ActiveCfg = Release|Any CPU {8994C820-7BA9-4BB8-B9EA-C608B07C4A11}.Release|Any CPU.Build.0 = Release|Any CPU - {FF176AD5-D6DA-41EE-B27D-1DBEF0CE462F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF176AD5-D6DA-41EE-B27D-1DBEF0CE462F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FF176AD5-D6DA-41EE-B27D-1DBEF0CE462F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FF176AD5-D6DA-41EE-B27D-1DBEF0CE462F}.Release|Any CPU.Build.0 = Release|Any CPU {69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Debug|Any CPU.Build.0 = Debug|Any CPU {69F1D68F-9CD5-4EA6-9B47-2A7A9BF8CED9}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/LibMpcApp/LibMpcApp.xproj b/LibMpcApp/LibMpcApp.xproj deleted file mode 100644 index b0a483b..0000000 --- a/LibMpcApp/LibMpcApp.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - ff176ad5-d6da-41ee-b27d-1dbef0ce462f - LibMpcApp - .\obj - .\bin\ - v4.5.2 - - - - 2.0 - - - diff --git a/LibMpcApp/Program.cs b/LibMpcApp/Program.cs deleted file mode 100644 index 688f0fa..0000000 --- a/LibMpcApp/Program.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Net; -using LibMpc; - -namespace LibMpcApp -{ - /// - /// Simple console app to test commands and parsed responses. - /// - public class Program - { - public static void Main(string[] args) - { - var mpc = new Mpc(new IPEndPoint(IPAddress.Loopback, 6600)); - - var connected = mpc.ConnectAsync().GetAwaiter().GetResult(); - if (connected) - { - Console.WriteLine("Connected to MPD."); - StartReadCommands(mpc); - } - else - { - Console.WriteLine("Could not connect to MPD."); - } - - mpc.DisconnectAsync().GetAwaiter().GetResult(); - } - - private static void StartReadCommands(Mpc mpc) - { - int userInput = 0; - while ((userInput = DisplayMenu()) != 99) - { - var response = new object(); - - switch (userInput) - { - case 11: - response = mpc.SendAsync(new Commands.Output.DisableOutput(0)).GetAwaiter().GetResult(); - break; - case 12: - response = mpc.SendAsync(new Commands.Output.EnableOutput(0)).GetAwaiter().GetResult(); - break; - case 13: - response = mpc.SendAsync(new Commands.Output.Outputs()).GetAwaiter().GetResult(); - break; - - case 24: - response = mpc.SendAsync(new Commands.Reflection.TagTypes()).GetAwaiter().GetResult(); - break; - - case 313: - response = mpc.SendAsync(new Commands.Database.Update()).GetAwaiter().GetResult(); - break; - } - - Console.WriteLine("Response: "); - Console.WriteLine(response); - } - } - - static public int DisplayMenu() - { - Console.WriteLine(); - Console.WriteLine("Commands: "); - - Console.WriteLine(); - Console.WriteLine("11. disableoutput 0"); - Console.WriteLine("12. enableoutput 0"); - Console.WriteLine("13. outputs"); - - Console.WriteLine(); - Console.WriteLine("Reflection"); - Console.WriteLine("24. tagtypes"); - - Console.WriteLine(); - Console.WriteLine("Database"); - Console.WriteLine("313. update"); - - Console.WriteLine(); - Console.WriteLine("99. Exit"); - Console.WriteLine(); - var result = Console.ReadLine(); - return Convert.ToInt32(result); - } - } -} diff --git a/LibMpcApp/Properties/AssemblyInfo.cs b/LibMpcApp/Properties/AssemblyInfo.cs deleted file mode 100644 index c72cd92..0000000 --- a/LibMpcApp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Windows User")] -[assembly: AssemblyProduct("LibMpcApp")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("ff176ad5-d6da-41ee-b27d-1dbef0ce462f")] diff --git a/LibMpcApp/project.json b/LibMpcApp/project.json deleted file mode 100644 index b24b498..0000000 --- a/LibMpcApp/project.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": "1.0.0-*", - "buildOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "LibMpc": "1.0.0-*", - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.1" - } - }, - - "frameworks": { - "netcoreapp1.0": { - "imports": "dnxcore50" - } - } -} From e2ebbe7e1466eecc630707c54b9c51b1965db8e2 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 11:03:28 +0100 Subject: [PATCH 08/24] Output commands completed + test --- LibMpc/Commands/Commands.Output.cs | 21 ++++++++++++++- LibMpcTest/LibMpcTest.cs | 9 ------- LibMpcTest/MpcMock.cs | 4 +-- LibMpcTest/MpdMock.cs | 14 +++++----- LibMpcTest/TestOutput.cs | 12 +++++++++ LibMpcTest/Tests/DatabaseCommandsTest.cs | 8 +++--- LibMpcTest/Tests/OutputCommandsTest.cs | 30 +++++++++++++++++----- LibMpcTest/Tests/ReflectionCommandsTest.cs | 4 +-- 8 files changed, 71 insertions(+), 31 deletions(-) create mode 100644 LibMpcTest/TestOutput.cs diff --git a/LibMpc/Commands/Commands.Output.cs b/LibMpc/Commands/Commands.Output.cs index 54725ef..0597d37 100644 --- a/LibMpc/Commands/Commands.Output.cs +++ b/LibMpc/Commands/Commands.Output.cs @@ -52,7 +52,26 @@ namespace LibMpc } } - // TODO: toggleoutput // Turns an output on or off, depending on the current state. + /// + /// Turns an output on or off, depending on the current state. + /// + public class ToggleOutput : IMpcCommand + { + private readonly int _outputId; + + public ToggleOutput(int outputId) + { + _outputId = outputId; + } + + public string Value => string.Join(" ", "toggleoutput", _outputId); + + public string FormatResponse(IList> response) + { + // Response should be empty. + return string.Join(", ", response); + } + } /// /// Shows information about all outputs. diff --git a/LibMpcTest/LibMpcTest.cs b/LibMpcTest/LibMpcTest.cs index bb77415..a88a16a 100644 --- a/LibMpcTest/LibMpcTest.cs +++ b/LibMpcTest/LibMpcTest.cs @@ -1,5 +1,4 @@ using LibMpc; -using System.Diagnostics; using Xunit; namespace LibMpcTest @@ -13,12 +12,4 @@ namespace LibMpcTest internal Mpc Mpc { get; } } - - internal class TestUtils - { - internal static void WriteLine(string value) - { - Debug.WriteLine(value); - } - } } diff --git a/LibMpcTest/MpcMock.cs b/LibMpcTest/MpcMock.cs index f75264d..51ab76c 100644 --- a/LibMpcTest/MpcMock.cs +++ b/LibMpcTest/MpcMock.cs @@ -12,7 +12,7 @@ namespace LibMpcTest Client = new Mpc(new IPEndPoint(IPAddress.Loopback, 6600)); var connected = Task.Run(async () => await Client.ConnectAsync()).Result; - TestUtils.WriteLine($"Connected to MPD : {connected}"); + TestOutput.WriteLine($"Connected to MPD : {connected}"); } public Mpc Client { get; } @@ -20,7 +20,7 @@ namespace LibMpcTest public void Dispose() { Client?.DisconnectAsync().GetAwaiter().GetResult(); - TestUtils.WriteLine($"Disconnected from MPD."); + TestOutput.WriteLine($"Disconnected from MPD."); } } } \ No newline at end of file diff --git a/LibMpcTest/MpdMock.cs b/LibMpcTest/MpdMock.cs index e0935dd..de5b289 100644 --- a/LibMpcTest/MpdMock.cs +++ b/LibMpcTest/MpdMock.cs @@ -32,11 +32,11 @@ namespace LibMpcTest } }; - TestUtils.WriteLine($"Starting Server: {Process.StartInfo.FileName} {Process.StartInfo.Arguments}"); + TestOutput.WriteLine($"Starting Server: {Process.StartInfo.FileName} {Process.StartInfo.Arguments}"); Process.Start(); - TestUtils.WriteLine($"Output: {Process.StandardOutput.ReadToEnd()}"); - TestUtils.WriteLine($"Error: {Process.StandardError.ReadToEnd()}"); + TestOutput.WriteLine($"Output: {Process.StandardOutput.ReadToEnd()}"); + TestOutput.WriteLine($"Error: {Process.StandardError.ReadToEnd()}"); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { @@ -80,16 +80,16 @@ namespace LibMpcTest netcat.Start(); netcat.WaitForExit(); - TestUtils.WriteLine(command); - TestUtils.WriteLine($"Output: {netcat.StandardOutput.ReadToEnd()}"); - TestUtils.WriteLine($"Error: {netcat.StandardError.ReadToEnd()}"); + TestOutput.WriteLine(command); + TestOutput.WriteLine($"Output: {netcat.StandardOutput.ReadToEnd()}"); + TestOutput.WriteLine($"Error: {netcat.StandardError.ReadToEnd()}"); } public void Dispose() { Process?.Kill(); Process?.Dispose(); - TestUtils.WriteLine("Server Stopped."); + TestOutput.WriteLine("Server Stopped."); } private class Server diff --git a/LibMpcTest/TestOutput.cs b/LibMpcTest/TestOutput.cs new file mode 100644 index 0000000..bb67d96 --- /dev/null +++ b/LibMpcTest/TestOutput.cs @@ -0,0 +1,12 @@ +using System; + +namespace LibMpcTest +{ + internal class TestOutput + { + internal static void WriteLine(string value) + { + Console.Out.WriteLine(value); + } + } +} \ No newline at end of file diff --git a/LibMpcTest/Tests/DatabaseCommandsTest.cs b/LibMpcTest/Tests/DatabaseCommandsTest.cs index 16b28b8..e8a7c56 100644 --- a/LibMpcTest/Tests/DatabaseCommandsTest.cs +++ b/LibMpcTest/Tests/DatabaseCommandsTest.cs @@ -13,8 +13,8 @@ namespace LibMpcTest { var response = await Mpc.SendAsync(new Commands.Database.ListAll()); - TestUtils.WriteLine("ListAllTest Result:"); - TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine("ListAllTest Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); Assert.True(response.Response.Body.Count().Equals(7)); } @@ -24,8 +24,8 @@ namespace LibMpcTest { var response = await Mpc.SendAsync(new Commands.Database.Find(MpdTags.Genre, "soundfx")); - TestUtils.WriteLine("FindGenreTest Result:"); - TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine("FindGenreTest Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); Assert.True(response.Response.Body.Count().Equals(6)); } diff --git a/LibMpcTest/Tests/OutputCommandsTest.cs b/LibMpcTest/Tests/OutputCommandsTest.cs index c46a35b..264c363 100644 --- a/LibMpcTest/Tests/OutputCommandsTest.cs +++ b/LibMpcTest/Tests/OutputCommandsTest.cs @@ -16,8 +16,8 @@ namespace LibMpcTest var response = await Mpc.SendAsync(new Commands.Output.DisableOutput(2)); - TestUtils.WriteLine("DisableOutputTest Result:"); - TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine("DisableOutputTest Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); Assert.True(response.Response.Body.Equals(string.Empty)); Assert.True(response.Response.State.Status.Equals("OK")); @@ -35,8 +35,8 @@ namespace LibMpcTest var response = await Mpc.SendAsync(new Commands.Output.EnableOutput(1)); - TestUtils.WriteLine("EnableOutputTest Result:"); - TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine("EnableOutputTest Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); Assert.True(response.Response.Body.Equals(string.Empty)); Assert.True(response.Response.State.Status.Equals("OK")); @@ -45,13 +45,31 @@ namespace LibMpcTest Assert.True(responseOutputs.Response.Body.Single(output => output.Id.Equals(1)).IsEnabled); } + [Fact] + public async Task ToggleOutputTest() + { + var responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs()); + Assert.True(responseOutputs.Response.Body.Single(output => output.Id.Equals(2)).IsEnabled); + + var response = await Mpc.SendAsync(new Commands.Output.ToggleOutput(2)); + + TestOutput.WriteLine("ToggleOutputTest Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Equals(string.Empty)); + Assert.True(response.Response.State.Status.Equals("OK")); + + responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs()); + Assert.False(responseOutputs.Response.Body.Single(output => output.Id.Equals(2)).IsEnabled); + } + [Fact] public async Task LisOutputsTest() { var response = await Mpc.SendAsync(new Commands.Output.Outputs()); - TestUtils.WriteLine("LisOutputsTest Result:"); - TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine("LisOutputsTest Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); Assert.True(response.Response.Body.Count().Equals(3)); } diff --git a/LibMpcTest/Tests/ReflectionCommandsTest.cs b/LibMpcTest/Tests/ReflectionCommandsTest.cs index 4067373..4f3afe7 100644 --- a/LibMpcTest/Tests/ReflectionCommandsTest.cs +++ b/LibMpcTest/Tests/ReflectionCommandsTest.cs @@ -13,8 +13,8 @@ namespace LibMpcTest { var response = await Mpc.SendAsync(new Commands.Reflection.TagTypes()); - TestUtils.WriteLine("TagTypesTest Result:"); - TestUtils.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + TestOutput.WriteLine("TagTypesTest Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); Assert.True(response.Response.Body.Count().Equals(17)); } From b7791ab26afc6931023a8f218aa9a196649830b4 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 11:11:10 +0100 Subject: [PATCH 09/24] Mpd config with one audio output for each test. --- LibMpcTest/MpdConf.cs | 6 +++--- LibMpcTest/Tests/OutputCommandsTest.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/LibMpcTest/MpdConf.cs b/LibMpcTest/MpdConf.cs index 0570f42..fa6dbde 100644 --- a/LibMpcTest/MpdConf.cs +++ b/LibMpcTest/MpdConf.cs @@ -28,19 +28,19 @@ namespace LibMpcTest builder.AppendLine("port \"6600\""); builder.AppendLine("audio_output {"); builder.AppendLine("type \"null\""); - builder.AppendLine("name \"Output One\""); + builder.AppendLine("name \"Enabled output to be disabled\""); builder.AppendLine("enabled \"true\""); builder.AppendLine("mixer_type \"none\""); builder.AppendLine("}"); builder.AppendLine("audio_output {"); builder.AppendLine("type \"null\""); - builder.AppendLine("name \"Output Two\""); + builder.AppendLine("name \"Disabled output to be enabled\""); builder.AppendLine("enabled \"false\""); builder.AppendLine("mixer_type \"none\""); builder.AppendLine("}"); builder.AppendLine("audio_output {"); builder.AppendLine("type \"null\""); - builder.AppendLine("name \"Output Three\""); + builder.AppendLine("name \"Enabled output to be toggled\""); builder.AppendLine("enabled \"true\""); builder.AppendLine("mixer_type \"none\""); builder.AppendLine("}"); diff --git a/LibMpcTest/Tests/OutputCommandsTest.cs b/LibMpcTest/Tests/OutputCommandsTest.cs index 264c363..d055646 100644 --- a/LibMpcTest/Tests/OutputCommandsTest.cs +++ b/LibMpcTest/Tests/OutputCommandsTest.cs @@ -12,9 +12,9 @@ namespace LibMpcTest public async Task DisableOutputTest() { var responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs()); - Assert.True(responseOutputs.Response.Body.Single(output => output.Id.Equals(2)).IsEnabled); + Assert.True(responseOutputs.Response.Body.Single(output => output.Id.Equals(0)).IsEnabled); - var response = await Mpc.SendAsync(new Commands.Output.DisableOutput(2)); + var response = await Mpc.SendAsync(new Commands.Output.DisableOutput(0)); TestOutput.WriteLine("DisableOutputTest Result:"); TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); @@ -23,7 +23,7 @@ namespace LibMpcTest Assert.True(response.Response.State.Status.Equals("OK")); responseOutputs = await Mpc.SendAsync(new Commands.Output.Outputs()); - Assert.False(responseOutputs.Response.Body.Single(output => output.Id.Equals(2)).IsEnabled); + Assert.False(responseOutputs.Response.Body.Single(output => output.Id.Equals(0)).IsEnabled); } [Fact] From 36a48887890c66a9f79811995b2040fef73874aa Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 11:19:26 +0100 Subject: [PATCH 10/24] "Commands" command created and tested --- LibMpc/Commands/Commands.Reflection.cs | 17 ++++++++++++++++- LibMpcTest/Tests/ReflectionCommandsTest.cs | 11 +++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/LibMpc/Commands/Commands.Reflection.cs b/LibMpc/Commands/Commands.Reflection.cs index 9d4506e..90140bf 100644 --- a/LibMpc/Commands/Commands.Reflection.cs +++ b/LibMpc/Commands/Commands.Reflection.cs @@ -11,7 +11,22 @@ namespace LibMpc public static class Reflection { // TODO: config - // TODO: commands + + /// + /// Shows which commands the current user has access to. + /// + public class Commands : IMpcCommand> + { + public string Value => "commands"; + + public IEnumerable FormatResponse(IList> response) + { + var result = response.Where(item => item.Key.Equals("command")).Select(item => item.Value); + + return result; + } + } + // TODO: notcommands public class TagTypes : IMpcCommand> diff --git a/LibMpcTest/Tests/ReflectionCommandsTest.cs b/LibMpcTest/Tests/ReflectionCommandsTest.cs index 4f3afe7..9830732 100644 --- a/LibMpcTest/Tests/ReflectionCommandsTest.cs +++ b/LibMpcTest/Tests/ReflectionCommandsTest.cs @@ -8,6 +8,17 @@ namespace LibMpcTest { public partial class LibMpcTest { + [Fact] + public async Task CommandsTest() + { + var response = await Mpc.SendAsync(new Commands.Reflection.Commands()); + + TestOutput.WriteLine($"CommandsTest (commands: {response.Response.Body.Count()}) Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Count().Equals(84)); + } + [Fact] public async Task TagTypesTest() { From 4cb95df50f62fc789f5339db2190d0cdd6597def Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 11:26:42 +0100 Subject: [PATCH 11/24] CommandsTest fixed --- LibMpcTest/Tests/ReflectionCommandsTest.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/LibMpcTest/Tests/ReflectionCommandsTest.cs b/LibMpcTest/Tests/ReflectionCommandsTest.cs index 9830732..3676fa6 100644 --- a/LibMpcTest/Tests/ReflectionCommandsTest.cs +++ b/LibMpcTest/Tests/ReflectionCommandsTest.cs @@ -16,7 +16,9 @@ namespace LibMpcTest TestOutput.WriteLine($"CommandsTest (commands: {response.Response.Body.Count()}) Result:"); TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); - Assert.True(response.Response.Body.Count().Equals(84)); + // Different answer from MPD on Windows and on Linux, beacuse of Version. + // Check only if response is not empty + Assert.True(response.Response.Body.Any()); } [Fact] From ef57b0a76bd79663c59d0b571219fdccf4d33b4b Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 11:31:48 +0100 Subject: [PATCH 12/24] UrlHandlers command implemented and tested. Print MPD version in test. --- LibMpc/Commands/Commands.Reflection.cs | 13 ++++++++++++- LibMpc/Mpc.cs | 1 + LibMpcTest/MpcMock.cs | 2 +- LibMpcTest/Tests/ReflectionCommandsTest.cs | 11 +++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/LibMpc/Commands/Commands.Reflection.cs b/LibMpc/Commands/Commands.Reflection.cs index 90140bf..15f6282 100644 --- a/LibMpc/Commands/Commands.Reflection.cs +++ b/LibMpc/Commands/Commands.Reflection.cs @@ -41,7 +41,18 @@ namespace LibMpc } } - // TODO: urlhandlers + public class UrlHandlers : IMpcCommand> + { + public string Value => "urlhandlers"; + + public IEnumerable FormatResponse(IList> response) + { + var result = response.Where(item => item.Key.Equals("handler")).Select(item => item.Value); + + return result; + } + } + // TODO: decoders } } diff --git a/LibMpc/Mpc.cs b/LibMpc/Mpc.cs index 1a23a04..0952a41 100644 --- a/LibMpc/Mpc.cs +++ b/LibMpc/Mpc.cs @@ -24,6 +24,7 @@ namespace LibMpc } public bool IsConnected => _connection?.IsConnected ?? false; + public string Version => _connection?.Version ?? "Unknown"; public async Task ConnectAsync() { diff --git a/LibMpcTest/MpcMock.cs b/LibMpcTest/MpcMock.cs index 51ab76c..986e935 100644 --- a/LibMpcTest/MpcMock.cs +++ b/LibMpcTest/MpcMock.cs @@ -12,7 +12,7 @@ namespace LibMpcTest Client = new Mpc(new IPEndPoint(IPAddress.Loopback, 6600)); var connected = Task.Run(async () => await Client.ConnectAsync()).Result; - TestOutput.WriteLine($"Connected to MPD : {connected}"); + TestOutput.WriteLine($"Connected to MPD : {connected}; Version: {Client.Version}"); } public Mpc Client { get; } diff --git a/LibMpcTest/Tests/ReflectionCommandsTest.cs b/LibMpcTest/Tests/ReflectionCommandsTest.cs index 3676fa6..b24fcbe 100644 --- a/LibMpcTest/Tests/ReflectionCommandsTest.cs +++ b/LibMpcTest/Tests/ReflectionCommandsTest.cs @@ -31,5 +31,16 @@ namespace LibMpcTest Assert.True(response.Response.Body.Count().Equals(17)); } + + [Fact] + public async Task UrlHandlersTest() + { + var response = await Mpc.SendAsync(new Commands.Reflection.UrlHandlers()); + + TestOutput.WriteLine($"UrlHandlersTest (handlers: {response.Response.Body.Count()}) Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Count().Equals(11)); + } } } \ No newline at end of file From ed2604f81b7ffe2291644b427813ba71363461d7 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 12:04:59 +0100 Subject: [PATCH 13/24] UrlHandlersTest fixed --- LibMpcTest/Tests/ReflectionCommandsTest.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/LibMpcTest/Tests/ReflectionCommandsTest.cs b/LibMpcTest/Tests/ReflectionCommandsTest.cs index b24fcbe..2818489 100644 --- a/LibMpcTest/Tests/ReflectionCommandsTest.cs +++ b/LibMpcTest/Tests/ReflectionCommandsTest.cs @@ -17,8 +17,13 @@ namespace LibMpcTest TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); // Different answer from MPD on Windows and on Linux, beacuse of Version. - // Check only if response is not empty - Assert.True(response.Response.Body.Any()); + // Check some of the commands. + Assert.True(response.Response.Body.Any(command => command.Equals("listall"))); + Assert.True(response.Response.Body.Any(command => command.Equals("outputs"))); + Assert.True(response.Response.Body.Any(command => command.Equals("pause"))); + Assert.True(response.Response.Body.Any(command => command.Equals("play"))); + Assert.True(response.Response.Body.Any(command => command.Equals("setvol"))); + Assert.True(response.Response.Body.Any(command => command.Equals("stop"))); } [Fact] @@ -40,7 +45,12 @@ namespace LibMpcTest TestOutput.WriteLine($"UrlHandlersTest (handlers: {response.Response.Body.Count()}) Result:"); TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); - Assert.True(response.Response.Body.Count().Equals(11)); + // Different answer from MPD on Windows and on Linux. + // Check some of the handlers. + Assert.True(response.Response.Body.Any(handler => handler.Equals("http://"))); + Assert.True(response.Response.Body.Any(handler => handler.Equals("mms://"))); + Assert.True(response.Response.Body.Any(handler => handler.Equals("gopher://"))); + Assert.True(response.Response.Body.Any(handler => handler.Equals("rtp://"))); } } } \ No newline at end of file From 89990d5e8180e0a673b8161aed539b8102032a72 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 12:10:13 +0100 Subject: [PATCH 14/24] Decoders command + test. Still to Assert response depending on build server. --- LibMpc/Commands/Commands.Reflection.cs | 37 +++- LibMpc/Types/MpdDecoderPlugin.cs | 36 ++++ LibMpc/Types/MpdFile.cs | 202 ++++++++++----------- LibMpcTest/Tests/ReflectionCommandsTest.cs | 11 ++ 4 files changed, 184 insertions(+), 102 deletions(-) create mode 100644 LibMpc/Types/MpdDecoderPlugin.cs diff --git a/LibMpc/Commands/Commands.Reflection.cs b/LibMpc/Commands/Commands.Reflection.cs index 15f6282..5a7ea32 100644 --- a/LibMpc/Commands/Commands.Reflection.cs +++ b/LibMpc/Commands/Commands.Reflection.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using LibMpc.Types; namespace LibMpc { @@ -53,7 +54,41 @@ namespace LibMpc } } - // TODO: decoders + public class Decoders : IMpcCommand> + { + public string Value => "decoders"; + + public IEnumerable FormatResponse(IList> response) + { + var result = new List(); + + var mpdDecoderPlugin = MpdDecoderPlugin.Empty; + foreach (var line in response) + { + if (line.Key.Equals("plugin")) + { + if (mpdDecoderPlugin.IsInitialized) + { + result.Add(mpdDecoderPlugin); + } + + mpdDecoderPlugin = new MpdDecoderPlugin(line.Value); + } + + if (line.Key.Equals("suffix") && mpdDecoderPlugin.IsInitialized) + { + mpdDecoderPlugin.AddSuffix(line.Value); + } + + if (line.Key.Equals("mime_type") && mpdDecoderPlugin.IsInitialized) + { + mpdDecoderPlugin.AddMediaType(line.Value); + } + } + + return result; + } + } } } } diff --git a/LibMpc/Types/MpdDecoderPlugin.cs b/LibMpc/Types/MpdDecoderPlugin.cs new file mode 100644 index 0000000..ede4f43 --- /dev/null +++ b/LibMpc/Types/MpdDecoderPlugin.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; + +namespace LibMpc.Types +{ + public class MpdDecoderPlugin + { + public static readonly MpdDecoderPlugin Empty = new MpdDecoderPlugin(string.Empty); + + private readonly IList _suffixes = new List(); + private readonly IList _mediaTypes = new List(); + + public MpdDecoderPlugin(string name) + { + name.CheckNotNull(); + + Name = name; + IsInitialized = !string.IsNullOrEmpty(name); + } + + public string Name { get; } + public IEnumerable Suffixes => _suffixes; + public IEnumerable MediaTypes => _mediaTypes; + + internal bool IsInitialized { get; } + + internal void AddSuffix(string suffix) + { + _suffixes.Add(suffix); + } + + internal void AddMediaType(string type) + { + _mediaTypes.Add(type); + } + } +} \ No newline at end of file diff --git a/LibMpc/Types/MpdFile.cs b/LibMpc/Types/MpdFile.cs index 12a15c3..c57372f 100644 --- a/LibMpc/Types/MpdFile.cs +++ b/LibMpc/Types/MpdFile.cs @@ -1,106 +1,106 @@ -using System.Collections.Generic; - -namespace LibMpc.Types -{ - /// - /// The MpdFile class contains all meta data for a file of the MPD. - /// - public class MpdFile - { - public static readonly MpdFile EmptyFile = new MpdFile(string.Empty); - - private const string TagTime = "Time"; - private const string TagArtist = "Artist"; - private const string TagAlbum = "Album"; - private const string TagTitle = "Title"; - private const string TagTrack = "Track"; - private const string TagName = "Name"; - private const string TagGenre = "Genre"; - private const string TagDate = "Date"; - private const string TagComposer = "Composer"; - private const string TagPerformer = "Performer"; - private const string TagComment = "Comment"; - private const string TagDisc = "Disc"; - private const string TagPos = "Pos"; - private const string TagId = "Id"; - - private readonly IDictionary _unknownTags = new Dictionary(); - - public MpdFile(string file) - { - File = file; - IsInitialized = !string.IsNullOrEmpty(File); - } - - public string File { get; } - public int Time { get; private set; } = -1; - public string Album { get; private set; } = string.Empty; - public string Artist { get; private set; } = string.Empty; - public string Title { get; private set; } = string.Empty; - public string Track { get; private set; } = string.Empty; - public string Name { get; private set; } = string.Empty; - public string Genre { get; private set; } = string.Empty; - public string Date { get; private set; } = string.Empty; - public string Composer { get; private set; } = string.Empty; - public string Performer { get; private set; } = string.Empty; - public string Comment { get; private set; } = string.Empty; - public int Disc { get; private set; } = -1; - public int Pos { get; private set; } = -1; - public int Id { get; private set; } = -1; - public IDictionary UnknownTags => _unknownTags; - - internal bool IsInitialized { get; } - - internal void AddTag(string tag, string value) - { - switch (tag) - { - case TagTime: - Time = int.Parse(value); - break; - case TagArtist: - Artist = value; - break; - case TagAlbum: - Album = value; - break; - case TagTitle: - Title = value; - break; - case TagTrack: - Track = value; - break; - case TagName: - Name = value; - break; - case TagGenre: - Genre = value; - break; - case TagDate: - Date = value; - break; - case TagComposer: - Composer = value; - break; - case TagPerformer: - Performer = value; +using System.Collections.Generic; + +namespace LibMpc.Types +{ + /// + /// The MpdFile class contains all meta data for a file of the MPD. + /// + public class MpdFile + { + public static readonly MpdFile EmptyFile = new MpdFile(string.Empty); + + private const string TagTime = "Time"; + private const string TagArtist = "Artist"; + private const string TagAlbum = "Album"; + private const string TagTitle = "Title"; + private const string TagTrack = "Track"; + private const string TagName = "Name"; + private const string TagGenre = "Genre"; + private const string TagDate = "Date"; + private const string TagComposer = "Composer"; + private const string TagPerformer = "Performer"; + private const string TagComment = "Comment"; + private const string TagDisc = "Disc"; + private const string TagPos = "Pos"; + private const string TagId = "Id"; + + private readonly IDictionary _unknownTags = new Dictionary(); + + public MpdFile(string file) + { + File = file; + IsInitialized = !string.IsNullOrEmpty(File); + } + + public string File { get; } + public int Time { get; private set; } = -1; + public string Album { get; private set; } = string.Empty; + public string Artist { get; private set; } = string.Empty; + public string Title { get; private set; } = string.Empty; + public string Track { get; private set; } = string.Empty; + public string Name { get; private set; } = string.Empty; + public string Genre { get; private set; } = string.Empty; + public string Date { get; private set; } = string.Empty; + public string Composer { get; private set; } = string.Empty; + public string Performer { get; private set; } = string.Empty; + public string Comment { get; private set; } = string.Empty; + public int Disc { get; private set; } = -1; + public int Pos { get; private set; } = -1; + public int Id { get; private set; } = -1; + public IDictionary UnknownTags => _unknownTags; + + internal bool IsInitialized { get; } + + internal void AddTag(string tag, string value) + { + switch (tag) + { + case TagTime: + Time = int.Parse(value); break; - case TagComment: - Comment = value; + case TagArtist: + Artist = value; break; - case TagDisc: - Disc = int.Parse(value); + case TagAlbum: + Album = value; break; - case TagPos: - Pos = int.Parse(value); + case TagTitle: + Title = value; break; - case TagId: - Id = int.Parse(value); + case TagTrack: + Track = value; break; - default: - _unknownTags.Add(tag, value); - break; - } - } - } -} + case TagName: + Name = value; + break; + case TagGenre: + Genre = value; + break; + case TagDate: + Date = value; + break; + case TagComposer: + Composer = value; + break; + case TagPerformer: + Performer = value; + break; + case TagComment: + Comment = value; + break; + case TagDisc: + Disc = int.Parse(value); + break; + case TagPos: + Pos = int.Parse(value); + break; + case TagId: + Id = int.Parse(value); + break; + default: + _unknownTags.Add(tag, value); + break; + } + } + } +} diff --git a/LibMpcTest/Tests/ReflectionCommandsTest.cs b/LibMpcTest/Tests/ReflectionCommandsTest.cs index 2818489..91f7879 100644 --- a/LibMpcTest/Tests/ReflectionCommandsTest.cs +++ b/LibMpcTest/Tests/ReflectionCommandsTest.cs @@ -52,5 +52,16 @@ namespace LibMpcTest Assert.True(response.Response.Body.Any(handler => handler.Equals("gopher://"))); Assert.True(response.Response.Body.Any(handler => handler.Equals("rtp://"))); } + + [Fact] + public async Task DecodersTest() + { + var response = await Mpc.SendAsync(new Commands.Reflection.Decoders()); + + TestOutput.WriteLine($"DecodersTest (decoders: {response.Response.Body.Count()}) Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + // TODO: Assert + } } } \ No newline at end of file From 9b163f32a8d5fa4abe5ea4188ab99d1271ce5ff8 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 12:20:16 +0100 Subject: [PATCH 15/24] Asserts for DecodersTest --- LibMpcTest/Tests/ReflectionCommandsTest.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/LibMpcTest/Tests/ReflectionCommandsTest.cs b/LibMpcTest/Tests/ReflectionCommandsTest.cs index 91f7879..a4e2a48 100644 --- a/LibMpcTest/Tests/ReflectionCommandsTest.cs +++ b/LibMpcTest/Tests/ReflectionCommandsTest.cs @@ -61,7 +61,20 @@ namespace LibMpcTest TestOutput.WriteLine($"DecodersTest (decoders: {response.Response.Body.Count()}) Result:"); TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); - // TODO: Assert + // Different answer from MPD on Windows and on Linux. + // Check some of the decoders. + Assert.True(response.Response.Body.Any(decoder => decoder.Name.Equals("mad"))); + Assert.True(response.Response.Body.Any(decoder => decoder.Suffixes.Any(suffix => suffix.Equals("mp3")))); + Assert.True(response.Response.Body.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/mpeg")))); + Assert.True(response.Response.Body.Any(decoder => decoder.Name.Equals("flac"))); + Assert.True(response.Response.Body.Any(decoder => decoder.Suffixes.Any(suffix => suffix.Equals("flac")))); + Assert.True(response.Response.Body.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/flac")))); + Assert.True(response.Response.Body.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/x-flac")))); + Assert.True(response.Response.Body.Any(decoder => decoder.Name.Equals("ffmpeg"))); + Assert.True(response.Response.Body.Any(decoder => decoder.Suffixes.Any(suffix => suffix.Equals("aac")))); + Assert.True(response.Response.Body.Any(decoder => decoder.Suffixes.Any(suffix => suffix.Equals("mpeg")))); + Assert.True(response.Response.Body.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/aac")))); + Assert.True(response.Response.Body.Any(decoder => decoder.MediaTypes.Any(mediaType => mediaType.Equals("audio/mpeg")))); } } } \ No newline at end of file From 6829b8cf05484305640c76119ca30826cadb64d7 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 12:21:46 +0100 Subject: [PATCH 16/24] Comments --- LibMpc/Commands/Commands.Reflection.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/LibMpc/Commands/Commands.Reflection.cs b/LibMpc/Commands/Commands.Reflection.cs index 5a7ea32..fb8f061 100644 --- a/LibMpc/Commands/Commands.Reflection.cs +++ b/LibMpc/Commands/Commands.Reflection.cs @@ -30,6 +30,9 @@ namespace LibMpc // TODO: notcommands + /// + /// Shows a list of available song metadata. + /// public class TagTypes : IMpcCommand> { public string Value => "tagtypes"; @@ -42,6 +45,9 @@ namespace LibMpc } } + /// + /// Gets a list of available URL handlers. + /// public class UrlHandlers : IMpcCommand> { public string Value => "urlhandlers"; @@ -54,6 +60,9 @@ namespace LibMpc } } + /// + /// Print a list of decoder plugins, followed by their supported suffixes and MIME types. + /// public class Decoders : IMpcCommand> { public string Value => "decoders"; From 03800369b66bddf53321467570b227b3cd449055 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 12:35:41 +0100 Subject: [PATCH 17/24] Comments --- LibMpc/Commands/Commands.Database.cs | 5 ++++- LibMpc/Commands/Commands.Reflection.cs | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/LibMpc/Commands/Commands.Database.cs b/LibMpc/Commands/Commands.Database.cs index fe9eb31..3d4a1cd 100644 --- a/LibMpc/Commands/Commands.Database.cs +++ b/LibMpc/Commands/Commands.Database.cs @@ -12,7 +12,10 @@ namespace LibMpc public class Database { // TODO: count - + + /// + /// Finds songs in the database that is exactly "searchText". + /// public class Find : IMpcCommand> { private readonly ITag _tag; diff --git a/LibMpc/Commands/Commands.Reflection.cs b/LibMpc/Commands/Commands.Reflection.cs index fb8f061..0bd954c 100644 --- a/LibMpc/Commands/Commands.Reflection.cs +++ b/LibMpc/Commands/Commands.Reflection.cs @@ -11,7 +11,7 @@ namespace LibMpc /// public static class Reflection { - // TODO: config + // config : This command is only permitted to "local" clients (connected via UNIX domain socket). /// /// Shows which commands the current user has access to. @@ -28,7 +28,7 @@ namespace LibMpc } } - // TODO: notcommands + // TODO: notcommands : Shows which commands the current user does not have access to. /// /// Shows a list of available song metadata. From 16619f7c44cc166407e6a7aea931d7bfb2e5aef8 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 14:54:57 +0100 Subject: [PATCH 18/24] Class for Playlist commands added. Test playlists created. --- LibMpc/Commands/Commands.Playlists.cs | 24 ++++++++++++++++++++ LibMpcTest/Server/Playlists/Playlist One.m3u | 5 ++++ LibMpcTest/Server/Playlists/Playlist Two.m3u | 3 +++ LibMpcTest/Server/Playlists/_My Playlist.m3u | 5 ++++ LibMpcTest/Server/Playlists/dummy | 0 5 files changed, 37 insertions(+) create mode 100644 LibMpc/Commands/Commands.Playlists.cs create mode 100644 LibMpcTest/Server/Playlists/Playlist One.m3u create mode 100644 LibMpcTest/Server/Playlists/Playlist Two.m3u create mode 100644 LibMpcTest/Server/Playlists/_My Playlist.m3u delete mode 100644 LibMpcTest/Server/Playlists/dummy diff --git a/LibMpc/Commands/Commands.Playlists.cs b/LibMpc/Commands/Commands.Playlists.cs new file mode 100644 index 0000000..72df4aa --- /dev/null +++ b/LibMpc/Commands/Commands.Playlists.cs @@ -0,0 +1,24 @@ +namespace LibMpc +{ + public partial class Commands + { + public static class Playlists + { + /// + /// https://www.musicpd.org/doc/protocol/queue.html + /// + public static class Current + { + + } + + /// + /// https://www.musicpd.org/doc/protocol/playlist_files.html + /// + public static class Stored + { + + } + } + } +} \ No newline at end of file diff --git a/LibMpcTest/Server/Playlists/Playlist One.m3u b/LibMpcTest/Server/Playlists/Playlist One.m3u new file mode 100644 index 0000000..7001dbe --- /dev/null +++ b/LibMpcTest/Server/Playlists/Playlist One.m3u @@ -0,0 +1,5 @@ +teaspoon-stirring-mug-of-coffee.mp3 +whistle-kettle-boiling.mp3 +wine-glass-double-chink-clink-cheers.mp3 +Directory With Spaces/coin-spin-light.mp3 +Directory With Spaces/finger-snap-click.mp3 diff --git a/LibMpcTest/Server/Playlists/Playlist Two.m3u b/LibMpcTest/Server/Playlists/Playlist Two.m3u new file mode 100644 index 0000000..98e2fb4 --- /dev/null +++ b/LibMpcTest/Server/Playlists/Playlist Two.m3u @@ -0,0 +1,3 @@ +A long name directory with some spaces/pouring-water-into-mug-of-coffee.mp3 +A long name directory with some spaces/Sub Directory Two/short-trouser-pants-zip-closing.mp3 +Directory/2-Kids-Laughing.mp3 diff --git a/LibMpcTest/Server/Playlists/_My Playlist.m3u b/LibMpcTest/Server/Playlists/_My Playlist.m3u new file mode 100644 index 0000000..5d6f216 --- /dev/null +++ b/LibMpcTest/Server/Playlists/_My Playlist.m3u @@ -0,0 +1,5 @@ +A long name directory with some spaces/Ghost-Sounds.mp3 +Directory/ambient-noise-server-room.mp3 +Directory With Spaces/SubDirectory One/central-locking-Ford-Mondeo-Mk-3.mp3 +_My Directory/gas-fire-lighting.mp3 +A long name directory with some spaces/Sub Directory Two/starting-engine-Ford-Mondeo-Mk-3-diesel.mp3 diff --git a/LibMpcTest/Server/Playlists/dummy b/LibMpcTest/Server/Playlists/dummy deleted file mode 100644 index e69de29..0000000 From b12ded8121ee6c5360a84b22108f83cf5153b149 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 15:26:09 +0100 Subject: [PATCH 19/24] listplaylists command created + test. --- LibMpc/Commands/Commands.Playlists.cs | 33 +++++++++++++++++++++-- LibMpc/Message/MpdMessage.cs | 2 +- LibMpc/Types/MpdPlaylist.cs | 23 ++++++++++++++++ LibMpcTest/Tests/PlaylistsCommandsTest.cs | 22 +++++++++++++++ 4 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 LibMpc/Types/MpdPlaylist.cs create mode 100644 LibMpcTest/Tests/PlaylistsCommandsTest.cs diff --git a/LibMpc/Commands/Commands.Playlists.cs b/LibMpc/Commands/Commands.Playlists.cs index 72df4aa..f4356f5 100644 --- a/LibMpc/Commands/Commands.Playlists.cs +++ b/LibMpc/Commands/Commands.Playlists.cs @@ -1,4 +1,8 @@ -namespace LibMpc +using System.Collections.Generic; +using System.Linq; +using LibMpc.Types; + +namespace LibMpc { public partial class Commands { @@ -17,7 +21,32 @@ /// public static class Stored { - + /// + /// Prints a list of the playlist directory. + /// + public class ListPlaylists : IMpcCommand> + { + public string Value => "listplaylists"; + + public IEnumerable FormatResponse(IList> response) + { + var result = new List(); + + foreach (var line in response) + { + if (line.Key.Equals("playlist")) + { + result.Add(new MpdPlaylist(line.Value)); + } + else if (line.Key.Equals("Last-Modified")) + { + result.Last().AddLastModified(line.Value); + } + } + + return result; + } + } } } } diff --git a/LibMpc/Message/MpdMessage.cs b/LibMpc/Message/MpdMessage.cs index 186136e..8fb6234 100644 --- a/LibMpc/Message/MpdMessage.cs +++ b/LibMpc/Message/MpdMessage.cs @@ -15,7 +15,7 @@ namespace LibMpc [DebuggerDisplay("Request: {Request.Command.Value} | Response Status: {Response.State.Status}")] public class MpdMessage : IMpdMessage { - private readonly Regex _linePattern = new Regex("^(?[A-Za-z_]*):[ ]{0,1}(?.*)$"); + private readonly Regex _linePattern = new Regex("^(?[A-Za-z_-]*):[ ]{0,1}(?.*)$"); private readonly IList _rawResponse; public MpdMessage(IMpcCommand command, bool connected, IReadOnlyCollection response) diff --git a/LibMpc/Types/MpdPlaylist.cs b/LibMpc/Types/MpdPlaylist.cs new file mode 100644 index 0000000..7485433 --- /dev/null +++ b/LibMpc/Types/MpdPlaylist.cs @@ -0,0 +1,23 @@ +using System; +using System.Globalization; + +namespace LibMpc.Types +{ + public class MpdPlaylist + { + public MpdPlaylist(string name) + { + name.CheckNotNull(); + + Name = name; + } + + public string Name { get; } + public DateTime LastModified { get; private set; } + + internal void AddLastModified(string lastModified) + { + LastModified = DateTime.Parse(lastModified, CultureInfo.InvariantCulture); + } + } +} diff --git a/LibMpcTest/Tests/PlaylistsCommandsTest.cs b/LibMpcTest/Tests/PlaylistsCommandsTest.cs new file mode 100644 index 0000000..7f95242 --- /dev/null +++ b/LibMpcTest/Tests/PlaylistsCommandsTest.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Newtonsoft.Json; +using Xunit; +using LibMpc; +using System.Linq; + +namespace LibMpcTest +{ + public partial class LibMpcTest + { + [Fact] + public async Task ListPlaylistsTest() + { + var response = await Mpc.SendAsync(new Commands.Playlists.Stored.ListPlaylists()); + + TestOutput.WriteLine($"ListPlaylistsTest Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Count().Equals(3)); + } + } +} From ba83fbd8242133d2d000bcc352926915e03e0dc1 Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 15:42:48 +0100 Subject: [PATCH 20/24] Bug in find command fixed. --- LibMpc/Commands/Commands.Database.cs | 14 ++++-------- LibMpc/Types/IMpdFile.cs | 28 ++++++++++++++++++++++++ LibMpc/Types/MpdFile.cs | 9 +++----- LibMpcTest/Tests/DatabaseCommandsTest.cs | 2 +- 4 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 LibMpc/Types/IMpdFile.cs diff --git a/LibMpc/Commands/Commands.Database.cs b/LibMpc/Commands/Commands.Database.cs index 3d4a1cd..a791b8a 100644 --- a/LibMpc/Commands/Commands.Database.cs +++ b/LibMpc/Commands/Commands.Database.cs @@ -16,7 +16,7 @@ namespace LibMpc /// /// Finds songs in the database that is exactly "searchText". /// - public class Find : IMpcCommand> + public class Find : IMpcCommand> { private readonly ITag _tag; private readonly string _searchText; @@ -29,25 +29,19 @@ namespace LibMpc public string Value => string.Join(" ", "find", _tag.Value, _searchText); - public IEnumerable FormatResponse(IList> response) + public IEnumerable FormatResponse(IList> response) { var results = new List(); - var mpdFile = MpdFile.EmptyFile; foreach (var line in response) { if (line.Key.Equals("file")) { - if (mpdFile.IsInitialized) - { - results.Add(mpdFile); - } - - mpdFile = new MpdFile(line.Value); + results.Add(new MpdFile(line.Value)); } else { - mpdFile.AddTag(line.Key, line.Value); + results.Last().AddTag(line.Key, line.Value); } } diff --git a/LibMpc/Types/IMpdFile.cs b/LibMpc/Types/IMpdFile.cs new file mode 100644 index 0000000..2c2ed69 --- /dev/null +++ b/LibMpc/Types/IMpdFile.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace LibMpc.Types +{ + public interface IMpdFilePath + { + string File { get; } + } + + public interface IMpdFile : IMpdFilePath + { + int Time { get; } + string Album { get; } + string Artist { get; } + string Title { get; } + string Track { get; } + string Name { get; } + string Genre { get; } + string Date { get; } + string Composer { get; } + string Performer { get; } + string Comment { get; } + int Disc { get; } + int Pos { get; } + int Id { get; } + IDictionary UnknownTags { get; } + } +} \ No newline at end of file diff --git a/LibMpc/Types/MpdFile.cs b/LibMpc/Types/MpdFile.cs index c57372f..22133e1 100644 --- a/LibMpc/Types/MpdFile.cs +++ b/LibMpc/Types/MpdFile.cs @@ -5,10 +5,8 @@ namespace LibMpc.Types /// /// The MpdFile class contains all meta data for a file of the MPD. /// - public class MpdFile + public class MpdFile : IMpdFile { - public static readonly MpdFile EmptyFile = new MpdFile(string.Empty); - private const string TagTime = "Time"; private const string TagArtist = "Artist"; private const string TagAlbum = "Album"; @@ -28,8 +26,9 @@ namespace LibMpc.Types public MpdFile(string file) { + file.CheckNotNull(); + File = file; - IsInitialized = !string.IsNullOrEmpty(File); } public string File { get; } @@ -49,8 +48,6 @@ namespace LibMpc.Types public int Id { get; private set; } = -1; public IDictionary UnknownTags => _unknownTags; - internal bool IsInitialized { get; } - internal void AddTag(string tag, string value) { switch (tag) diff --git a/LibMpcTest/Tests/DatabaseCommandsTest.cs b/LibMpcTest/Tests/DatabaseCommandsTest.cs index e8a7c56..b6194cc 100644 --- a/LibMpcTest/Tests/DatabaseCommandsTest.cs +++ b/LibMpcTest/Tests/DatabaseCommandsTest.cs @@ -27,7 +27,7 @@ namespace LibMpcTest TestOutput.WriteLine("FindGenreTest Result:"); TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); - Assert.True(response.Response.Body.Count().Equals(6)); + Assert.True(response.Response.Body.Count().Equals(7)); } } } \ No newline at end of file From 092240c22f88c17c09f1245fbd43024863c5737d Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 15:48:44 +0100 Subject: [PATCH 21/24] MpdDirectory contains now only files path. --- LibMpc/MpdDirectoryListing.cs | 10 +++++----- LibMpc/Types/MpdDirectory.cs | 4 ++-- LibMpc/Types/MpdFile.cs | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/LibMpc/MpdDirectoryListing.cs b/LibMpc/MpdDirectoryListing.cs index cb8b3f9..322d8c7 100644 --- a/LibMpc/MpdDirectoryListing.cs +++ b/LibMpc/MpdDirectoryListing.cs @@ -10,13 +10,13 @@ namespace LibMpc /// public class MpdDirectoryListing { - private readonly ReadOnlyCollection file; + private readonly ReadOnlyCollection file; private readonly ReadOnlyCollection directory; private readonly ReadOnlyCollection playlist; /// /// The list of files in the directory. /// - public ReadOnlyCollection FileList { get { return this.file; } } + public ReadOnlyCollection FileList { get { return this.file; } } /// /// The list of subdirectories in the directory. /// @@ -31,7 +31,7 @@ namespace LibMpc /// The list of files in the directory. /// The list of subdirectories in the directory. /// The list of playlists in the directory. - public MpdDirectoryListing(List file, List directory, List playlist) + public MpdDirectoryListing(List file, List directory, List playlist) { if (file == null) throw new ArgumentNullException("file"); @@ -40,7 +40,7 @@ namespace LibMpc if (playlist == null) throw new ArgumentNullException("playlist"); - this.file = new ReadOnlyCollection(file); + this.file = new ReadOnlyCollection(file); this.directory = new ReadOnlyCollection(directory); this.playlist = new ReadOnlyCollection(playlist); } @@ -50,7 +50,7 @@ namespace LibMpc /// The list of files in the directory. /// The list of subdirectories in the directory. /// The list of playlists in the directory. - public MpdDirectoryListing(ReadOnlyCollection file, ReadOnlyCollection directory, ReadOnlyCollection playlist) + public MpdDirectoryListing(ReadOnlyCollection file, ReadOnlyCollection directory, ReadOnlyCollection playlist) { if (file == null) throw new ArgumentNullException("file"); diff --git a/LibMpc/Types/MpdDirectory.cs b/LibMpc/Types/MpdDirectory.cs index 561288f..a3e4bf5 100644 --- a/LibMpc/Types/MpdDirectory.cs +++ b/LibMpc/Types/MpdDirectory.cs @@ -5,7 +5,7 @@ namespace LibMpc.Types { public class MpdDirectory { - private readonly IList _files = new List(); + private readonly IList _files = new List(); public MpdDirectory(string path) { @@ -19,7 +19,7 @@ namespace LibMpc.Types public string Path { get; } public string Name { get; } - public IEnumerable Files => _files; + public IEnumerable Files => _files; internal void AddFile(string file) { diff --git a/LibMpc/Types/MpdFile.cs b/LibMpc/Types/MpdFile.cs index 22133e1..fc4023d 100644 --- a/LibMpc/Types/MpdFile.cs +++ b/LibMpc/Types/MpdFile.cs @@ -5,7 +5,7 @@ namespace LibMpc.Types /// /// The MpdFile class contains all meta data for a file of the MPD. /// - public class MpdFile : IMpdFile + internal class MpdFile : IMpdFile { private const string TagTime = "Time"; private const string TagArtist = "Artist"; @@ -24,7 +24,7 @@ namespace LibMpc.Types private readonly IDictionary _unknownTags = new Dictionary(); - public MpdFile(string file) + internal MpdFile(string file) { file.CheckNotNull(); From 982a013839a01e8f031c04fc1c6eeff25907520f Mon Sep 17 00:00:00 2001 From: glucaci Date: Tue, 20 Dec 2016 16:17:06 +0100 Subject: [PATCH 22/24] ListPlaylist command implemeted + test. --- LibMpc/Commands/Commands.Playlists.cs | 19 +++++++++++++++++++ LibMpcTest/Tests/PlaylistsCommandsTest.cs | 14 ++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/LibMpc/Commands/Commands.Playlists.cs b/LibMpc/Commands/Commands.Playlists.cs index f4356f5..0d5bb67 100644 --- a/LibMpc/Commands/Commands.Playlists.cs +++ b/LibMpc/Commands/Commands.Playlists.cs @@ -21,6 +21,25 @@ namespace LibMpc /// public static class Stored { + public class ListPlaylist : IMpcCommand> + { + private readonly string _playlistName; + + public ListPlaylist(string playlistName) + { + _playlistName = playlistName; + } + + public string Value => string.Join(" ", "listplaylist", $"\"{_playlistName}\""); + + public IEnumerable FormatResponse(IList> response) + { + var results = response.Where(line => line.Key.Equals("file")).Select(line => new MpdFile(line.Value)); + + return results; + } + } + /// /// Prints a list of the playlist directory. /// diff --git a/LibMpcTest/Tests/PlaylistsCommandsTest.cs b/LibMpcTest/Tests/PlaylistsCommandsTest.cs index 7f95242..41a0a26 100644 --- a/LibMpcTest/Tests/PlaylistsCommandsTest.cs +++ b/LibMpcTest/Tests/PlaylistsCommandsTest.cs @@ -8,6 +8,20 @@ namespace LibMpcTest { public partial class LibMpcTest { + [Theory] + [InlineData("Playlist One", 5)] + [InlineData("Playlist Two", 3)] + [InlineData("_My Playlist", 5)] + public async Task ListPlaylistTest(string playlistName, int numberOfFiles) + { + var response = await Mpc.SendAsync(new Commands.Playlists.Stored.ListPlaylist(playlistName)); + + TestOutput.WriteLine($"ListPlaylistTest (playlistName: {playlistName}) Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Count().Equals(numberOfFiles)); + } + [Fact] public async Task ListPlaylistsTest() { From 5ea5d24b7a53d43221d2eb3835b0d7ec9ef64c6d Mon Sep 17 00:00:00 2001 From: glucaci Date: Wed, 21 Dec 2016 11:40:50 +0100 Subject: [PATCH 23/24] Naming --- LibMpc/Types/IMpdFile.cs | 2 +- LibMpc/Types/MpdFile.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LibMpc/Types/IMpdFile.cs b/LibMpc/Types/IMpdFile.cs index 2c2ed69..7507d65 100644 --- a/LibMpc/Types/IMpdFile.cs +++ b/LibMpc/Types/IMpdFile.cs @@ -23,6 +23,6 @@ namespace LibMpc.Types int Disc { get; } int Pos { get; } int Id { get; } - IDictionary UnknownTags { get; } + IDictionary UnknownMetadata { get; } } } \ No newline at end of file diff --git a/LibMpc/Types/MpdFile.cs b/LibMpc/Types/MpdFile.cs index fc4023d..7c9a3ca 100644 --- a/LibMpc/Types/MpdFile.cs +++ b/LibMpc/Types/MpdFile.cs @@ -22,7 +22,7 @@ namespace LibMpc.Types private const string TagPos = "Pos"; private const string TagId = "Id"; - private readonly IDictionary _unknownTags = new Dictionary(); + private readonly IDictionary _unknownMetadata = new Dictionary(); internal MpdFile(string file) { @@ -46,7 +46,7 @@ namespace LibMpc.Types public int Disc { get; private set; } = -1; public int Pos { get; private set; } = -1; public int Id { get; private set; } = -1; - public IDictionary UnknownTags => _unknownTags; + public IDictionary UnknownMetadata => _unknownMetadata; internal void AddTag(string tag, string value) { @@ -95,7 +95,7 @@ namespace LibMpc.Types Id = int.Parse(value); break; default: - _unknownTags.Add(tag, value); + _unknownMetadata.Add(tag, value); break; } } From 679748b2079b10aeb0cad2efa840078221d1e35f Mon Sep 17 00:00:00 2001 From: glucaci Date: Mon, 30 Jan 2017 11:52:35 +0100 Subject: [PATCH 24/24] ListPlaylistInfo command and UnitTest. --- LibMpc/Commands/Commands.Playlists.cs | 31 +++++++++++++++++++++++ LibMpcTest/Tests/PlaylistsCommandsTest.cs | 18 +++++++++++++ 2 files changed, 49 insertions(+) diff --git a/LibMpc/Commands/Commands.Playlists.cs b/LibMpc/Commands/Commands.Playlists.cs index 0d5bb67..9250ab3 100644 --- a/LibMpc/Commands/Commands.Playlists.cs +++ b/LibMpc/Commands/Commands.Playlists.cs @@ -40,6 +40,37 @@ namespace LibMpc } } + public class ListPlaylistInfo : IMpcCommand> + { + private readonly string _playlistName; + + public ListPlaylistInfo(string playlistName) + { + _playlistName = playlistName; + } + + public string Value => string.Join(" ", "listplaylistinfo", $"\"{_playlistName}\""); + + public IEnumerable FormatResponse(IList> response) + { + var results = new List(); + + foreach (var line in response) + { + if (line.Key.Equals("file")) + { + results.Add(new MpdFile(line.Value)); + } + else + { + results.Last().AddTag(line.Key, line.Value); + } + } + + return results; + } + } + /// /// Prints a list of the playlist directory. /// diff --git a/LibMpcTest/Tests/PlaylistsCommandsTest.cs b/LibMpcTest/Tests/PlaylistsCommandsTest.cs index 41a0a26..a65297c 100644 --- a/LibMpcTest/Tests/PlaylistsCommandsTest.cs +++ b/LibMpcTest/Tests/PlaylistsCommandsTest.cs @@ -3,6 +3,7 @@ using Newtonsoft.Json; using Xunit; using LibMpc; using System.Linq; +using Xunit.Abstractions; namespace LibMpcTest { @@ -22,6 +23,23 @@ namespace LibMpcTest Assert.True(response.Response.Body.Count().Equals(numberOfFiles)); } + [Theory] + [InlineData("Playlist One", 5)] + [InlineData("Playlist Two", 3)] + [InlineData("_My Playlist", 5)] + public async Task ListPlaylistInfoTest(string playlistName, int numberOfFiles) + { + var response = await Mpc.SendAsync(new Commands.Playlists.Stored.ListPlaylistInfo(playlistName)); + + TestOutput.WriteLine($"ListPlaylistTest (playlistName: {playlistName}) Result:"); + TestOutput.WriteLine(JsonConvert.SerializeObject(response, Formatting.Indented)); + + Assert.True(response.Response.Body.Count().Equals(numberOfFiles)); + Assert.True(response.Response.Body.All(item => !string.IsNullOrEmpty(item.Artist))); + Assert.True(response.Response.Body.All(item => !string.IsNullOrEmpty(item.Title))); + Assert.True(response.Response.Body.All(item => !string.IsNullOrEmpty(item.Date))); + } + [Fact] public async Task ListPlaylistsTest() {