From 113c37687491bac18191d0ffcd991a5933013ebe Mon Sep 17 00:00:00 2001
From: Javier Novoa <javier.novoa@outlook.com>
Date: Fri, 11 May 2018 16:25:05 -0500
Subject: [PATCH 1/7] Initial work

---
 .gitignore                                    |  6 ++++
 OpenMovieDatabaseNetClient.sln                | 32 +++++++++++++++++++
 .../OpenMovieDatabase.Client.csproj           |  7 ++++
 .../OpenMovieDatabaseClient.cs                | 24 ++++++++++++++
 4 files changed, 69 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 OpenMovieDatabaseNetClient.sln
 create mode 100644 src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
 create mode 100644 src/OpenMovieDatabase.Client/OpenMovieDatabaseClient.cs

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..83a45ea
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+﻿################################################################################
+# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
+################################################################################
+
+/.vs
+/src/**/obj
diff --git a/OpenMovieDatabaseNetClient.sln b/OpenMovieDatabaseNetClient.sln
new file mode 100644
index 0000000..6cfd7cf
--- /dev/null
+++ b/OpenMovieDatabaseNetClient.sln
@@ -0,0 +1,32 @@
+﻿
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.2000
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2CA15343-B21C-4678-AA1B-523E60BBD17B}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{4BAC450A-0F7C-42FE-90C8-C5CEB7FFE153}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMovieDatabase.Client", "src\OpenMovieDatabase.Client\OpenMovieDatabase.Client.csproj", "{6E58D769-A11D-4D74-AD80-2BD289E7E177}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6E58D769-A11D-4D74-AD80-2BD289E7E177}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6E58D769-A11D-4D74-AD80-2BD289E7E177}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6E58D769-A11D-4D74-AD80-2BD289E7E177}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6E58D769-A11D-4D74-AD80-2BD289E7E177}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{6E58D769-A11D-4D74-AD80-2BD289E7E177} = {2CA15343-B21C-4678-AA1B-523E60BBD17B}
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {332CCF9C-BB99-4084-87BF-4E746E132E2E}
+	EndGlobalSection
+EndGlobal
diff --git a/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj b/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
new file mode 100644
index 0000000..23103c9
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
@@ -0,0 +1,7 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard1.1</TargetFramework>
+  </PropertyGroup>
+
+</Project>
diff --git a/src/OpenMovieDatabase.Client/OpenMovieDatabaseClient.cs b/src/OpenMovieDatabase.Client/OpenMovieDatabaseClient.cs
new file mode 100644
index 0000000..784005c
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/OpenMovieDatabaseClient.cs
@@ -0,0 +1,24 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+
+namespace OpenMovieDatabase.Client
+{
+    public class OpenMovieDatabaseClient
+    {
+        private readonly HttpClient _httpClient;
+        private readonly string _apiKey;
+
+        public OpenMovieDatabaseClient(HttpClient httpClient, string apiKey)
+        {
+            if (string.IsNullOrEmpty(apiKey))
+                throw new ArgumentNullException(nameof(apiKey));
+
+            _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
+            _apiKey = apiKey;
+        }
+
+
+    }
+}

From 32d1e5bbb680e01421f67d583ae7d5d9a6ecfd80 Mon Sep 17 00:00:00 2001
From: Nelson Javier Novoa Tellez <javier.novoa@outlook.com>
Date: Wed, 27 Jun 2018 18:18:35 -0500
Subject: [PATCH 2/7] Add client operations, unit test, request/response
 objects

---
 .gitignore                                    |   3 +
 OpenMovieDatabaseNetClient.sln                |   7 +
 src/OpenMovieDatabase.Client/BaseRequest.cs   |  18 +++
 src/OpenMovieDatabase.Client/BasicResponse.cs |  33 +++++
 .../GetByIdOrTitleRequest.cs                  |  43 ++++++
 .../GetByIdOrTitleResponse.cs                 | 124 ++++++++++++++++++
 .../Internal/IInternalBaseResponse.cs         |   8 ++
 .../InternalGetByIdOrTitleResponse.cs         |  13 ++
 .../Internal/InternalSearchItem.cs            |  89 +++++++++++++
 .../Internal/InternalSearchResponse.cs        |  19 +++
 src/OpenMovieDatabase.Client/ItemType.cs      |  11 ++
 .../OpenMovieDatabase.Client.csproj           |   7 +
 .../OpenMovieDatabaseClient.cs                |  65 ++++++++-
 ...OpenMovieDatabaseEmptyResponseException.cs |  10 ++
 .../OpenMovieDatabaseException.cs             |  18 +++
 src/OpenMovieDatabase.Client/PlotType.cs      |   9 ++
 .../Properties/AssemblyInfo.cs                |   1 +
 src/OpenMovieDatabase.Client/SearchRequest.cs |  37 ++++++
 .../SearchResponse.cs                         |  23 ++++
 .../BasicResponseTest.cs                      |  13 ++
 .../OpenMovieDatabaseClientIntegrationTest.cs | 100 ++++++++++++++
 .../OpenMovieDatabase.Client.Test.csproj      |  27 ++++
 .../OpenMovieDatabaseClientTest.cs            |  82 ++++++++++++
 .../SearchRequestTest.cs                      |  26 ++++
 .../SearchResponseTest.cs                     |  20 +++
 25 files changed, 803 insertions(+), 3 deletions(-)
 create mode 100644 src/OpenMovieDatabase.Client/BaseRequest.cs
 create mode 100644 src/OpenMovieDatabase.Client/BasicResponse.cs
 create mode 100644 src/OpenMovieDatabase.Client/GetByIdOrTitleRequest.cs
 create mode 100644 src/OpenMovieDatabase.Client/GetByIdOrTitleResponse.cs
 create mode 100644 src/OpenMovieDatabase.Client/Internal/IInternalBaseResponse.cs
 create mode 100644 src/OpenMovieDatabase.Client/Internal/InternalGetByIdOrTitleResponse.cs
 create mode 100644 src/OpenMovieDatabase.Client/Internal/InternalSearchItem.cs
 create mode 100644 src/OpenMovieDatabase.Client/Internal/InternalSearchResponse.cs
 create mode 100644 src/OpenMovieDatabase.Client/ItemType.cs
 create mode 100644 src/OpenMovieDatabase.Client/OpenMovieDatabaseEmptyResponseException.cs
 create mode 100644 src/OpenMovieDatabase.Client/OpenMovieDatabaseException.cs
 create mode 100644 src/OpenMovieDatabase.Client/PlotType.cs
 create mode 100644 src/OpenMovieDatabase.Client/Properties/AssemblyInfo.cs
 create mode 100644 src/OpenMovieDatabase.Client/SearchRequest.cs
 create mode 100644 src/OpenMovieDatabase.Client/SearchResponse.cs
 create mode 100644 test/OpenMovieDatabase.Client.Test/BasicResponseTest.cs
 create mode 100644 test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs
 create mode 100644 test/OpenMovieDatabase.Client.Test/OpenMovieDatabase.Client.Test.csproj
 create mode 100644 test/OpenMovieDatabase.Client.Test/OpenMovieDatabaseClientTest.cs
 create mode 100644 test/OpenMovieDatabase.Client.Test/SearchRequestTest.cs
 create mode 100644 test/OpenMovieDatabase.Client.Test/SearchResponseTest.cs

diff --git a/.gitignore b/.gitignore
index 83a45ea..5199570 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,6 @@
 
 /.vs
 /src/**/obj
+/src/**/bin
+/test/**/obj
+/test/**/bin
diff --git a/OpenMovieDatabaseNetClient.sln b/OpenMovieDatabaseNetClient.sln
index 6cfd7cf..fcf81e3 100644
--- a/OpenMovieDatabaseNetClient.sln
+++ b/OpenMovieDatabaseNetClient.sln
@@ -9,6 +9,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{4BAC450A-0
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMovieDatabase.Client", "src\OpenMovieDatabase.Client\OpenMovieDatabase.Client.csproj", "{6E58D769-A11D-4D74-AD80-2BD289E7E177}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMovieDatabase.Client.Test", "test\OpenMovieDatabase.Client.Test\OpenMovieDatabase.Client.Test.csproj", "{4B611C1E-4494-466A-AA13-BC36C90A9C22}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -19,12 +21,17 @@ Global
 		{6E58D769-A11D-4D74-AD80-2BD289E7E177}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{6E58D769-A11D-4D74-AD80-2BD289E7E177}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{6E58D769-A11D-4D74-AD80-2BD289E7E177}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4B611C1E-4494-466A-AA13-BC36C90A9C22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4B611C1E-4494-466A-AA13-BC36C90A9C22}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4B611C1E-4494-466A-AA13-BC36C90A9C22}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4B611C1E-4494-466A-AA13-BC36C90A9C22}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(NestedProjects) = preSolution
 		{6E58D769-A11D-4D74-AD80-2BD289E7E177} = {2CA15343-B21C-4678-AA1B-523E60BBD17B}
+		{4B611C1E-4494-466A-AA13-BC36C90A9C22} = {4BAC450A-0F7C-42FE-90C8-C5CEB7FFE153}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {332CCF9C-BB99-4084-87BF-4E746E132E2E}
diff --git a/src/OpenMovieDatabase.Client/BaseRequest.cs b/src/OpenMovieDatabase.Client/BaseRequest.cs
new file mode 100644
index 0000000..7a5e9ef
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/BaseRequest.cs
@@ -0,0 +1,18 @@
+﻿using System;
+using System.Collections.Generic;
+namespace OpenMovieDatabase.Client
+{
+    public abstract class BaseRequest
+    {
+        protected readonly Dictionary<string, string> _parameters = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
+        {
+            ["r"] = "json",
+            ["v"] = "1"
+        };
+
+        internal IDictionary<string, string> GetParameters()
+        {
+            return _parameters;
+        }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/BasicResponse.cs b/src/OpenMovieDatabase.Client/BasicResponse.cs
new file mode 100644
index 0000000..c73aa37
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/BasicResponse.cs
@@ -0,0 +1,33 @@
+﻿using System;
+using OpenMovieDatabase.Client.Internal;
+namespace OpenMovieDatabase.Client
+{
+    public class BasicResponse
+    {
+        public string Title { get; }
+        public int Year { get; }
+        public string ImdbID { get; }
+        public ItemType Type { get; }
+        public Uri Poster { get; }
+
+        internal BasicResponse(InternalSearchItem item)
+        {
+            if (item == null)
+                throw new ArgumentNullException(nameof(item));
+
+            Title = item.Title;
+            Year = item.Year;
+            ImdbID = item.imdbID;
+            Type = (ItemType)Enum.Parse(typeof(ItemType), item.Type, true);
+            Poster = IsNullOrEmptyOrNA(item.Poster) ? null : new Uri(item.Poster);
+        }
+
+        protected static bool IsNullOrEmptyOrNA(string value)
+        {
+            if (string.IsNullOrEmpty(value))
+                return true;
+
+            return string.Equals("N/A", value, StringComparison.OrdinalIgnoreCase);
+        }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/GetByIdOrTitleRequest.cs b/src/OpenMovieDatabase.Client/GetByIdOrTitleRequest.cs
new file mode 100644
index 0000000..0d90a87
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/GetByIdOrTitleRequest.cs
@@ -0,0 +1,43 @@
+﻿using System;
+using System.Globalization;
+
+namespace OpenMovieDatabase.Client
+{
+    public class GetByIdOrTitleRequest : BaseRequest
+    {
+        public string ImdbId
+        {
+            get { return _parameters.ContainsKey("i") ? _parameters["i"] : null; }
+            set { _parameters["i"] = value; }
+        }
+
+        public string Title
+        {
+            get { return _parameters.ContainsKey("t") ? _parameters["t"] : null; }
+            set { _parameters["t"] = value; }
+        }
+
+        public ItemType Type
+        {
+            get { return (ItemType)Enum.Parse(typeof(ItemType), _parameters["type"], true); }
+            set { _parameters["type"] = value.ToString(); }
+        }
+
+        public int Year
+        {
+            get { return int.Parse(_parameters["y"], CultureInfo.InvariantCulture); }
+            set { _parameters["y"] = value.ToString(CultureInfo.InvariantCulture); }
+        }
+
+        public PlotType Plot
+        {
+            get { return (PlotType)Enum.Parse(typeof(PlotType), _parameters["plot"], true); }
+            set { _parameters["plot"] = value.ToString().ToLowerInvariant(); }
+        }
+
+        public GetByIdOrTitleRequest()
+        {
+            Plot = PlotType.Short;
+        }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/GetByIdOrTitleResponse.cs b/src/OpenMovieDatabase.Client/GetByIdOrTitleResponse.cs
new file mode 100644
index 0000000..b5fd7f1
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/GetByIdOrTitleResponse.cs
@@ -0,0 +1,124 @@
+﻿using System;
+using OpenMovieDatabase.Client.Internal;
+using System.Globalization;
+using System.Text.RegularExpressions;
+using System.Linq;
+
+namespace OpenMovieDatabase.Client
+{
+    public class GetByIdOrTitleResponse : BasicResponse
+    {
+        private static Regex _timeRegex = new Regex(@"^(\d{1,})+((\s{1})+min{1})$", RegexOptions.IgnoreCase);
+
+        public string Rated { get; set; }
+        public DateTime? Released { get; set; }
+        public TimeSpan? Runtime { get; set; }
+        public string[] Genre { get; set; }
+        public string[] Director { get; set; }
+        public string[] Writer { get; set; }
+        public string[] Actors { get; set; }
+        public string Plot { get; set; }
+        public string[] Language { get; set; }
+        public string[] Country { get; set; }
+        public string Awards { get; set; }
+        public Rating[] Ratings { get; set; }
+        public int Metascore { get; set; }
+        public float ImdbRating { get; set; }
+        public long? ImdbVotes { get; set; }
+        public DateTime? Dvd { get; set; }
+        public decimal? BoxOffice { get; set; }
+        public string Production { get; set; }
+        public Uri Website { get; set; }
+
+        internal GetByIdOrTitleResponse(InternalGetByIdOrTitleResponse item) : base(item)
+        {
+            if (item == null)
+                throw new ArgumentNullException(nameof(item));
+
+            Rated = IsNullOrEmptyOrNA(item.Rated) ? null : item.Rated;
+            Released = ParseOmdbDate(item.Released);
+            Runtime = ParseOmdbTime(item.Runtime);
+            Genre = SplitByColon(item.Genre);
+            Director = SplitByColon(item.Director);
+            Writer = SplitByColon(item.Writer);
+            Actors = SplitByColon(item.Actors);
+            Plot = item.Plot;
+            Language = SplitByColon(item.Language);
+            Country = SplitByColon(item.Country);
+            Awards = item.Awards;
+            Ratings = item.Ratings?.Select(r => new Rating(r)).ToArray();
+            Metascore = item.Metascore;
+            ImdbRating = item.imdbRating;
+            ImdbVotes = ParseOmdbNumber(item.imdbVotes);
+            Dvd = ParseOmdbDate(item.DVD);
+            BoxOffice = ParseOmdbNumber(item.BoxOffice);
+            Production = item.Production;
+            Website = IsNullOrEmptyOrNA(item.Website) ? null : new Uri(item.Website);
+        }
+
+        private static DateTime? ParseOmdbDate(string value)
+        {
+            if (IsNullOrEmptyOrNA(value))
+                return null;
+
+            if (DateTime.TryParseExact(value, "dd MMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out DateTime parsedValue))
+                return parsedValue;
+
+            return null;
+        }
+
+        private static TimeSpan? ParseOmdbTime(string value)
+        {
+            if (IsNullOrEmptyOrNA(value))
+                return null;
+
+            if (!_timeRegex.IsMatch(value))
+                return null;
+
+            if (int.TryParse(value.Replace(" min", ""), out int minutes))
+                return TimeSpan.FromMinutes(minutes);
+
+            return null;
+        }
+
+        private static string ParseOmdbString(string value)
+        {
+            if (IsNullOrEmptyOrNA(value))
+                return null;
+
+            return value;
+        }
+
+        private static string[] SplitByColon(string value)
+        {
+            if (IsNullOrEmptyOrNA(value))
+                return null;
+
+            return value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToArray();
+        }
+
+        private static long? ParseOmdbNumber(string value)
+        {
+            if (IsNullOrEmptyOrNA(value))
+                return null;
+
+            string normalizedNumber = value.Replace(",", "").Replace("$", "");
+            if (long.TryParse(normalizedNumber, out long number))
+                return number;
+
+            return null;
+        }
+    }
+
+    public class Rating
+    {
+        public string Source { get; }
+        public string Value { get; }
+
+        internal Rating(InternalRating rating)
+        {
+            Source = rating.Source;
+            Value = rating.Value;
+        }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/Internal/IInternalBaseResponse.cs b/src/OpenMovieDatabase.Client/Internal/IInternalBaseResponse.cs
new file mode 100644
index 0000000..f08725f
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/Internal/IInternalBaseResponse.cs
@@ -0,0 +1,8 @@
+﻿namespace OpenMovieDatabase.Client.Internal
+{
+    internal interface IInternalBaseResponse
+    {
+        bool Response { get; set; }
+        string Error { get; set; }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/Internal/InternalGetByIdOrTitleResponse.cs b/src/OpenMovieDatabase.Client/Internal/InternalGetByIdOrTitleResponse.cs
new file mode 100644
index 0000000..00c8632
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/Internal/InternalGetByIdOrTitleResponse.cs
@@ -0,0 +1,13 @@
+﻿using Newtonsoft.Json;
+
+namespace OpenMovieDatabase.Client.Internal
+{
+    internal class InternalGetByIdOrTitleResponse : InternalSearchItem, IInternalBaseResponse
+    {
+        [JsonProperty]
+        public bool Response { get; set; }
+
+        [JsonProperty]
+        public string Error { get; set; }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/Internal/InternalSearchItem.cs b/src/OpenMovieDatabase.Client/Internal/InternalSearchItem.cs
new file mode 100644
index 0000000..7408b98
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/Internal/InternalSearchItem.cs
@@ -0,0 +1,89 @@
+﻿using System;
+using Newtonsoft.Json;
+
+namespace OpenMovieDatabase.Client.Internal
+{
+    internal class InternalSearchItem
+    {
+        [JsonProperty]
+        internal string Title { get; set; }
+
+        [JsonProperty]
+        internal int Year { get; set; }
+
+        [JsonProperty]
+        internal string Rated { get; set; }
+
+        [JsonProperty]
+        internal string Released { get; set; }
+
+        [JsonProperty]
+        internal string Runtime { get; set; }
+
+        [JsonProperty]
+        internal string Genre { get; set; }
+
+        [JsonProperty]
+        internal string Director { get; set; }
+
+        [JsonProperty]
+        internal string Writer { get; set; }
+
+        [JsonProperty]
+        internal string Actors { get; set; }
+
+        [JsonProperty]
+        internal string Plot { get; set; }
+
+        [JsonProperty]
+        internal string Language { get; set; }
+
+        [JsonProperty]
+        internal string Country { get; set; }
+
+        [JsonProperty]
+        internal string Awards { get; set; }
+
+        [JsonProperty]
+        internal string Poster { get; set; }
+
+        [JsonProperty]
+        internal InternalRating[] Ratings { get; set; }
+
+        [JsonProperty]
+        internal int Metascore { get; set; }
+
+        [JsonProperty]
+        internal float imdbRating { get; set; }
+
+        [JsonProperty]
+        internal string imdbVotes { get; set; }
+
+        [JsonProperty]
+        internal string imdbID { get; set; }
+
+        [JsonProperty]
+        internal string Type { get; set; }
+
+        [JsonProperty]
+        internal string DVD { get; set; }
+
+        [JsonProperty]
+        internal string BoxOffice { get; set; }
+
+        [JsonProperty]
+        internal string Production { get; set; }
+
+        [JsonProperty]
+        internal string Website { get; set; }
+    }
+
+    internal class InternalRating
+    {
+        [JsonProperty]
+        internal string Source { get; set; }
+
+        [JsonProperty]
+        internal string Value { get; set; }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/Internal/InternalSearchResponse.cs b/src/OpenMovieDatabase.Client/Internal/InternalSearchResponse.cs
new file mode 100644
index 0000000..e28ba6e
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/Internal/InternalSearchResponse.cs
@@ -0,0 +1,19 @@
+﻿using Newtonsoft.Json;
+
+namespace OpenMovieDatabase.Client.Internal
+{
+    internal class InternalSearchResponse : IInternalBaseResponse
+    {
+        [JsonProperty]
+        public bool Response { get; set; }
+
+        [JsonProperty]
+        public string Error { get; set; }
+
+        [JsonProperty]
+        public InternalSearchItem[] Search { get; set; }
+
+        [JsonProperty]
+        public int TotalResults { get; set; }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/ItemType.cs b/src/OpenMovieDatabase.Client/ItemType.cs
new file mode 100644
index 0000000..2a653f8
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/ItemType.cs
@@ -0,0 +1,11 @@
+﻿using System;
+namespace OpenMovieDatabase.Client
+{
+    public enum ItemType
+    {
+        None,
+        Movie,
+        Series,
+        Episode
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj b/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
index 23103c9..f951400 100644
--- a/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
+++ b/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
@@ -4,4 +4,11 @@
     <TargetFramework>netstandard1.1</TargetFramework>
   </PropertyGroup>
 
+  <ItemGroup>
+    <Folder Include="Internal\" />
+    <Folder Include="Properties\" />
+  </ItemGroup>
+  <ItemGroup>
+    <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
+  </ItemGroup>
 </Project>
diff --git a/src/OpenMovieDatabase.Client/OpenMovieDatabaseClient.cs b/src/OpenMovieDatabase.Client/OpenMovieDatabaseClient.cs
index 784005c..b1c2199 100644
--- a/src/OpenMovieDatabase.Client/OpenMovieDatabaseClient.cs
+++ b/src/OpenMovieDatabase.Client/OpenMovieDatabaseClient.cs
@@ -1,7 +1,10 @@
 ﻿using System;
 using System.Collections.Generic;
 using System.Net.Http;
-using System.Text;
+using System.Threading.Tasks;
+using System.Linq;
+using OpenMovieDatabase.Client.Internal;
+using Newtonsoft.Json;
 
 namespace OpenMovieDatabase.Client
 {
@@ -10,13 +13,69 @@ public class OpenMovieDatabaseClient
         private readonly HttpClient _httpClient;
         private readonly string _apiKey;
 
-        public OpenMovieDatabaseClient(HttpClient httpClient, string apiKey)
+        public OpenMovieDatabaseClient(string apiKey, HttpClient httpClient)
         {
             if (string.IsNullOrEmpty(apiKey))
                 throw new ArgumentNullException(nameof(apiKey));
 
-            _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
             _apiKey = apiKey;
+            _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
+        }
+
+        public async Task<SearchResponse> SearchAsync(SearchRequest request)
+        {
+            if (request == null)
+                throw new ArgumentNullException(nameof(request));
+
+            if (string.IsNullOrEmpty(request.Term))
+                throw new ArgumentException("The term should not be empty", nameof(request));
+
+            var uri = GetUrlFromRequest(request);
+            var internalResponse = await HandleResponse<InternalSearchResponse>(_httpClient.GetAsync(uri));
+
+            return new SearchResponse(internalResponse);
+        }
+
+        public async Task<GetByIdOrTitleResponse> GetByIdOrTitleAsync(GetByIdOrTitleRequest request)
+        {
+            if (request == null)
+                throw new ArgumentNullException(nameof(request));
+
+            if (string.IsNullOrEmpty(request.Title) && string.IsNullOrEmpty(request.ImdbId))
+                throw new ArgumentException("Should set imdb id or tilte", nameof(request));
+
+            var uri = GetUrlFromRequest(request);
+            var internalResponse = await HandleResponse<InternalGetByIdOrTitleResponse>(_httpClient.GetAsync(uri));
+
+            return new GetByIdOrTitleResponse(internalResponse);
+        }
+
+        private Uri GetUrlFromRequest(BaseRequest request)
+        {
+            IDictionary<string, string> parameters = request.GetParameters();
+            parameters["apikey"] = _apiKey;
+
+            string queryString = string.Join("&", parameters.Select(p => $"{p.Key}={p.Value}").ToArray());
+            return new Uri($"http://www.omdbapi.com/?{queryString}");
+        }
+
+        private static async Task<T> HandleResponse<T>(Task<HttpResponseMessage> responseTask) where T : class, IInternalBaseResponse
+        {
+            HttpResponseMessage httpResponse = await responseTask;
+
+            httpResponse.EnsureSuccessStatusCode();
+
+            string content = await httpResponse.Content.ReadAsStringAsync();
+
+            var result = JsonConvert.DeserializeObject<T>(content);
+
+            if (result == null)
+                throw new EmptyResponseException();
+
+            if (!result.Response)
+                throw new OpenMovieDatabaseException(result);
+
+            return result;
         }
 
 
diff --git a/src/OpenMovieDatabase.Client/OpenMovieDatabaseEmptyResponseException.cs b/src/OpenMovieDatabase.Client/OpenMovieDatabaseEmptyResponseException.cs
new file mode 100644
index 0000000..ac2db35
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/OpenMovieDatabaseEmptyResponseException.cs
@@ -0,0 +1,10 @@
+﻿using System;
+namespace OpenMovieDatabase.Client
+{
+    public class EmptyResponseException : Exception
+    {
+        public EmptyResponseException() : base("There is not content present on response")
+        {
+        }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/OpenMovieDatabaseException.cs b/src/OpenMovieDatabase.Client/OpenMovieDatabaseException.cs
new file mode 100644
index 0000000..3277645
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/OpenMovieDatabaseException.cs
@@ -0,0 +1,18 @@
+﻿using System;
+using OpenMovieDatabase.Client.Internal;
+
+namespace OpenMovieDatabase.Client
+{
+    public class OpenMovieDatabaseException : Exception
+    {
+        internal OpenMovieDatabaseException(IInternalBaseResponse baseResponse) : base(baseResponse?.Error)
+        {
+            if (baseResponse == null)
+                throw new ArgumentNullException(nameof(baseResponse));
+
+            if (baseResponse.Response)
+                throw new ArgumentException("Response should not be a succeed one", nameof(baseResponse));
+
+        }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/PlotType.cs b/src/OpenMovieDatabase.Client/PlotType.cs
new file mode 100644
index 0000000..dc15387
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/PlotType.cs
@@ -0,0 +1,9 @@
+﻿using System;
+namespace OpenMovieDatabase.Client
+{
+    public enum PlotType
+    {
+        Short,
+        Full
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/Properties/AssemblyInfo.cs b/src/OpenMovieDatabase.Client/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..54a437b
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/Properties/AssemblyInfo.cs
@@ -0,0 +1 @@
+﻿[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("OpenMovieDatabase.Client.Test")]
\ No newline at end of file
diff --git a/src/OpenMovieDatabase.Client/SearchRequest.cs b/src/OpenMovieDatabase.Client/SearchRequest.cs
new file mode 100644
index 0000000..e71d47f
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/SearchRequest.cs
@@ -0,0 +1,37 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Globalization;
+namespace OpenMovieDatabase.Client
+{
+    public class SearchRequest : BaseRequest
+    {
+        public string Term
+        {
+            get { return _parameters["s"]; }
+            set { _parameters["s"] = value; }
+        }
+
+        public ItemType Type
+        {
+            get { return (ItemType)Enum.Parse(typeof(ItemType), _parameters["type"], true); }
+            set { _parameters["type"] = value.ToString().ToLowerInvariant(); }
+        }
+
+        public int Year
+        {
+            get { return int.Parse(_parameters["y"], CultureInfo.InvariantCulture); }
+            set { _parameters["y"] = value.ToString(CultureInfo.InvariantCulture); }
+        }
+
+        public int Page
+        {
+            get { return int.Parse(_parameters["page"], CultureInfo.InvariantCulture); }
+            set { _parameters["page"] = value.ToString(CultureInfo.InvariantCulture); }
+        }
+
+        public SearchRequest()
+        {
+            _parameters["page"] = "1";
+        }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/SearchResponse.cs b/src/OpenMovieDatabase.Client/SearchResponse.cs
new file mode 100644
index 0000000..904f8da
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/SearchResponse.cs
@@ -0,0 +1,23 @@
+﻿using System;
+using OpenMovieDatabase.Client.Internal;
+using System.Linq;
+namespace OpenMovieDatabase.Client
+{
+    public class SearchResponse
+    {
+        public BasicResponse[] Results { get; }
+        public int TotalResults { get; set; }
+
+        internal SearchResponse(InternalSearchResponse searchResponse)
+        {
+            if (searchResponse == null)
+                throw new ArgumentNullException(nameof(searchResponse));
+
+            if (!searchResponse.Response)
+                throw new ArgumentException("Should be a success response", nameof(searchResponse));
+
+            Results = searchResponse.Search?.Select(i => new BasicResponse(i)).ToArray();
+            TotalResults = searchResponse.TotalResults;
+        }
+    }
+}
diff --git a/test/OpenMovieDatabase.Client.Test/BasicResponseTest.cs b/test/OpenMovieDatabase.Client.Test/BasicResponseTest.cs
new file mode 100644
index 0000000..71f8b81
--- /dev/null
+++ b/test/OpenMovieDatabase.Client.Test/BasicResponseTest.cs
@@ -0,0 +1,13 @@
+﻿using System;
+using Xunit;
+namespace OpenMovieDatabase.Client.Test
+{
+    public class BasicResponseTest
+    {
+        [Fact]
+        public void ShouldThrowWhenParamIsNull()
+        {
+            Assert.Throws<ArgumentNullException>(() => new BasicResponse(null));
+        }
+    }
+}
diff --git a/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs b/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs
new file mode 100644
index 0000000..e3c6db5
--- /dev/null
+++ b/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs
@@ -0,0 +1,100 @@
+﻿using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Xunit;
+using System.Linq;
+
+namespace OpenMovieDatabase.Client.Test.Integration
+{
+    public class OpenMovieDatabaseClientIntegrationTest
+    {
+        private readonly OpenMovieDatabaseClient _sut;
+
+        public OpenMovieDatabaseClientIntegrationTest()
+        {
+            var handler = new HttpClientHandler
+            {
+                UseCookies = false,
+                AllowAutoRedirect = true,
+                ServerCertificateCustomValidationCallback = null
+            };
+
+             var httpClient = new HttpClient(handler);
+
+            //I'm using the same api key that http://www.omdbapi.com this could be stop working any moment
+            _sut = new OpenMovieDatabaseClient("PlzBanMe", httpClient);
+        }
+
+        [Fact]
+        //[Fact(Skip = "Integration test")]
+        public async Task SearchAsync()
+        {
+            var request = new SearchRequest
+            {
+                Term = "avengers",
+                Type = ItemType.Movie
+            };
+
+
+            var response = await _sut.SearchAsync(request);
+
+            Assert.NotNull(response);
+            Assert.Equal(75, response.TotalResults);
+            Assert.NotNull(response.Results);
+            Assert.NotEmpty(response.Results);
+            Assert.True(response.Results.All(r => r.Title.IndexOf(request.Term, StringComparison.OrdinalIgnoreCase) > -1));
+        }
+
+        [Fact]
+        //[Fact(Skip = "Integration test")]
+        public async Task SearchAsyncThrowsError()
+        {
+            var request = new SearchRequest
+            {
+                Term = "the",
+                Type = ItemType.Movie
+            };
+
+            await Assert.ThrowsAnyAsync<OpenMovieDatabaseException>(() => _sut.SearchAsync(request));
+        }
+
+        [Fact]
+        //[Fact(Skip = "Integration test")]
+        public async Task GetByIdOrTitleAsync()
+        {
+            var request = new GetByIdOrTitleRequest
+            {
+                ImdbId = "tt0499549",
+                Type = ItemType.Movie
+            };
+
+
+            var response = await _sut.GetByIdOrTitleAsync(request);
+
+            Assert.NotNull(response);
+            Assert.Equal("tt0499549", response.ImdbID);
+            Assert.Equal("Avatar", response.Title);
+
+            Assert.NotNull(response.Released);
+            Assert.Equal(18, response.Released.Value.Day);
+            Assert.Equal(12, response.Released.Value.Month);
+            Assert.Equal(2009, response.Released.Value.Year);
+
+            Assert.NotNull(response.Runtime);
+            Assert.Equal(162, response.Runtime.Value.TotalMinutes);
+        }
+
+        [Fact]
+        //[Fact(Skip = "Integration test")]
+        public async Task GetByIdOrTitleAsyncThrowsError()
+        {
+            var request = new GetByIdOrTitleRequest
+            {
+                ImdbId = "tt0000000",
+                Type = ItemType.Movie
+            };
+
+            await Assert.ThrowsAnyAsync<OpenMovieDatabaseException>(() => _sut.GetByIdOrTitleAsync(request));
+        }
+    }
+}
diff --git a/test/OpenMovieDatabase.Client.Test/OpenMovieDatabase.Client.Test.csproj b/test/OpenMovieDatabase.Client.Test/OpenMovieDatabase.Client.Test.csproj
new file mode 100644
index 0000000..4d1ad57
--- /dev/null
+++ b/test/OpenMovieDatabase.Client.Test/OpenMovieDatabase.Client.Test.csproj
@@ -0,0 +1,27 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+
+    <IsPackable>false</IsPackable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170628-02" />
+    <PackageReference Include="xunit" Version="2.2.0" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
+    <PackageReference Include="Moq" Version="4.8.3" />
+    <PackageReference Include="MockHttpClient" Version="1.0.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\OpenMovieDatabase.Client\OpenMovieDatabase.Client.csproj" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Remove="Properties\AssemblyInfo.cs" />
+    <Compile Remove="UnitTest1.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Integration\" />
+  </ItemGroup>
+</Project>
diff --git a/test/OpenMovieDatabase.Client.Test/OpenMovieDatabaseClientTest.cs b/test/OpenMovieDatabase.Client.Test/OpenMovieDatabaseClientTest.cs
new file mode 100644
index 0000000..cfa4811
--- /dev/null
+++ b/test/OpenMovieDatabase.Client.Test/OpenMovieDatabaseClientTest.cs
@@ -0,0 +1,82 @@
+﻿using System;
+using MockHttpClient;
+using Xunit;
+using System.Threading.Tasks;
+using System.Net;
+using System.Net.Http;
+
+namespace OpenMovieDatabase.Client.Test
+{
+    public static class OpenMovieDatabaseClientTest
+    {
+        public class Constructor
+        {
+            [Theory]
+            [InlineData("")]
+            [InlineData(null)]
+            public void ShouldThrowWhenApiKeyIsNullOrEmptyString(string apiKey)
+            {
+                Assert.Throws<ArgumentNullException>(() => new OpenMovieDatabaseClient(apiKey, null));
+            }
+
+            public void ShouldThrowWhenHttpClientIsNull()
+            {
+                Assert.Throws<ArgumentNullException>(() => new OpenMovieDatabaseClient("api-key", null));
+            }
+        }
+
+        public class SearchAsync
+        {
+            private readonly MockHttpClient.MockHttpClient _mockHttpClient;
+            private readonly OpenMovieDatabaseClient _sut;
+
+            public SearchAsync()
+            {
+                _mockHttpClient = new MockHttpClient.MockHttpClient();
+                _sut = new OpenMovieDatabaseClient("api-key", _mockHttpClient);
+            }
+
+            [Theory]
+            [InlineData(HttpStatusCode.InternalServerError)]
+            [InlineData(HttpStatusCode.NotFound)]
+            [InlineData(HttpStatusCode.BadRequest)]
+            public async Task ShouldThrowWhenResponseHasNotAnOkStatus(HttpStatusCode status)
+            {
+                var request = new SearchRequest
+                {
+                    Term = "test"
+                };
+
+                _mockHttpClient.When("http://www.omdbapi.com/*").Then((arg) => new HttpResponseMessage(status));
+
+                await Assert.ThrowsAnyAsync<Exception>(() => _sut.SearchAsync(request));
+            }
+
+            [Fact]
+            public async Task ShouldThrowWhenContentIsNull()
+            {
+                var request = new SearchRequest
+                {
+                    Term = "test"
+                };
+
+                _mockHttpClient.When("http://www.omdbapi.com/*").Then((arg) => new HttpResponseMessage(HttpStatusCode.OK).WithJsonContent(null));
+
+                await Assert.ThrowsAnyAsync<Exception>(() => _sut.SearchAsync(request));
+            }
+
+            [Fact]
+            public async Task ShouldThrowWhenContentIsNotNullAndResponseIsFalse()
+            {
+                var request = new SearchRequest
+                {
+                    Term = "test"
+                };
+
+                _mockHttpClient.When("http://www.omdbapi.com/*").Then((arg) => new HttpResponseMessage(HttpStatusCode.OK).WithJsonContent(new Internal.InternalSearchResponse { Response = false, Error = "Some Error" }));
+
+                await Assert.ThrowsAnyAsync<Exception>(() => _sut.SearchAsync(request));
+            }
+        }
+    }
+}
diff --git a/test/OpenMovieDatabase.Client.Test/SearchRequestTest.cs b/test/OpenMovieDatabase.Client.Test/SearchRequestTest.cs
new file mode 100644
index 0000000..fe0cad6
--- /dev/null
+++ b/test/OpenMovieDatabase.Client.Test/SearchRequestTest.cs
@@ -0,0 +1,26 @@
+﻿using System;
+using Xunit;
+namespace OpenMovieDatabase.Client.Test
+{
+    public class SearchRequestTest
+    {
+        private readonly SearchRequest _sut;
+
+        public SearchRequestTest()
+        {
+            _sut = new SearchRequest();
+        }
+
+        [Fact]
+        public void ShouldInitializeWithDefaultValues()
+        {
+            var parameters = _sut.GetParameters();
+
+            Assert.NotNull(parameters);
+            Assert.Equal(3, parameters.Count);
+            Assert.False(string.IsNullOrEmpty(parameters["page"]));
+            Assert.False(string.IsNullOrEmpty(parameters["r"]));
+            Assert.False(string.IsNullOrEmpty(parameters["v"]));
+        }
+    }
+}
diff --git a/test/OpenMovieDatabase.Client.Test/SearchResponseTest.cs b/test/OpenMovieDatabase.Client.Test/SearchResponseTest.cs
new file mode 100644
index 0000000..e3deca4
--- /dev/null
+++ b/test/OpenMovieDatabase.Client.Test/SearchResponseTest.cs
@@ -0,0 +1,20 @@
+﻿using System;
+using OpenMovieDatabase.Client.Internal;
+using Xunit;
+namespace OpenMovieDatabase.Client.Test
+{
+    public class SearchResponseTest
+    {
+        [Fact]
+        public void ShouldThrowWhenParamIsNull()
+        {
+            Assert.Throws<ArgumentNullException>(() => new SearchResponse(null));
+        }
+
+        [Fact]
+        public void ShouldThrowWhenResponseIsNotSuccess()
+        {
+            Assert.Throws<ArgumentException>(() => new SearchResponse(new InternalSearchResponse { Response = false }));
+        }
+    }
+}

From 47771bc926dcf75b7ecbd5290d59163882fb10c1 Mon Sep 17 00:00:00 2001
From: Nelson Javier Novoa Tellez <javier.novoa@outlook.com>
Date: Fri, 29 Jun 2018 17:52:58 -0500
Subject: [PATCH 3/7] Update readme file Add appveyor config

---
 README.md                                     | 12 +++++++
 appveyor.yml                                  | 34 +++++++++++++++++++
 .../OpenMovieDatabaseClientIntegrationTest.cs |  6 ++--
 3 files changed, 49 insertions(+), 3 deletions(-)
 create mode 100644 appveyor.yml

diff --git a/README.md b/README.md
index cf1521e..448f37d 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,14 @@
 # omdb-api-net-client
 Open Movie Database API .NET client
+
+Simple wrapper for .net (.NET Standard 1.1) of [Open Movie Database](https://www.omdbapi.com/). Enjoy it!!!
+
+## How to use it
+
+```csharp
+using OpenMovieDatabase.Client;
+...
+var omdbClient = new OpenMovieDatabaseClient(<your-api-key>, <yout HttpClient instance>)
+```
+
+
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..60ba603
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,34 @@
+configuration: Release
+image: Visual Studio 2017
+pull_requests:
+  - do_not_increment_build_number: true
+init:
+  # Good practise, because Windows line endings are different from Unix/Linux ones
+  - cmd: git config --global core.autocrlf true
+before_buid:
+  # Display .NET Core version
+  - cmd: dotnet --version
+  - cmd: dotnet restore ./src/src.csproj --verbosity m
+build:
+  project: OpenMovieDatabaseNetClient.sln
+  verbosity: normal
+  publish_nuget: true
+  publish_nuget_symbols: true
+
+#tests
+test:
+  # all except categories to test
+  categories:
+    except:
+      - Integration
+    
+#Push to nuget
+deploy:
+    provider: NuGet
+    api_key:
+        secure: wO5eiWkOc3xv1qM1mChKx6weYq9h795U6u5NJg6kqwdSgsXZVCXjQJk6G05MuPKC
+    skip_symbols: false
+    artifact: /.*\.nupkg/
+    on:
+      branch: master
+    
\ No newline at end of file
diff --git a/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs b/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs
index e3c6db5..b2228c6 100644
--- a/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs
+++ b/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs
@@ -26,7 +26,7 @@ public OpenMovieDatabaseClientIntegrationTest()
         }
 
         [Fact]
-        //[Fact(Skip = "Integration test")]
+        [Trait("Category", "Integration")]
         public async Task SearchAsync()
         {
             var request = new SearchRequest
@@ -45,8 +45,8 @@ public async Task SearchAsync()
             Assert.True(response.Results.All(r => r.Title.IndexOf(request.Term, StringComparison.OrdinalIgnoreCase) > -1));
         }
 
-        [Fact]
-        //[Fact(Skip = "Integration test")]
+        [Fact()]
+        [Trait("Category", "Integration")]
         public async Task SearchAsyncThrowsError()
         {
             var request = new SearchRequest

From cbc6b3db7839b7538e05b7d17db335d7f75e6db8 Mon Sep 17 00:00:00 2001
From: Javier Novoa <javier.novoa@outlook.com>
Date: Fri, 29 Jun 2018 20:32:33 -0500
Subject: [PATCH 4/7] Fix appveyor file Update nuget package data

---
 OpenMovieDatabaseNetClient.sln                   | 14 +++++++-------
 appveyor.yml                                     | 12 +++++++-----
 .../OpenMovieDatabase.Client.csproj              |  9 +++++++++
 .../OpenMovieDatabase.Client.Test.csproj         | 16 +++++-----------
 4 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/OpenMovieDatabaseNetClient.sln b/OpenMovieDatabaseNetClient.sln
index fcf81e3..33668e8 100644
--- a/OpenMovieDatabaseNetClient.sln
+++ b/OpenMovieDatabaseNetClient.sln
@@ -7,9 +7,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2CA15343-B21
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{4BAC450A-0F7C-42FE-90C8-C5CEB7FFE153}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMovieDatabase.Client", "src\OpenMovieDatabase.Client\OpenMovieDatabase.Client.csproj", "{6E58D769-A11D-4D74-AD80-2BD289E7E177}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenMovieDatabase.Client", "src\OpenMovieDatabase.Client\OpenMovieDatabase.Client.csproj", "{6E58D769-A11D-4D74-AD80-2BD289E7E177}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMovieDatabase.Client.Test", "test\OpenMovieDatabase.Client.Test\OpenMovieDatabase.Client.Test.csproj", "{4B611C1E-4494-466A-AA13-BC36C90A9C22}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMovieDatabase.Client.Test", "test\OpenMovieDatabase.Client.Test\OpenMovieDatabase.Client.Test.csproj", "{22958135-6A79-445D-88AC-CCEB40544FFA}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -21,17 +21,17 @@ Global
 		{6E58D769-A11D-4D74-AD80-2BD289E7E177}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{6E58D769-A11D-4D74-AD80-2BD289E7E177}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{6E58D769-A11D-4D74-AD80-2BD289E7E177}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4B611C1E-4494-466A-AA13-BC36C90A9C22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4B611C1E-4494-466A-AA13-BC36C90A9C22}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4B611C1E-4494-466A-AA13-BC36C90A9C22}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4B611C1E-4494-466A-AA13-BC36C90A9C22}.Release|Any CPU.Build.0 = Release|Any CPU
+		{22958135-6A79-445D-88AC-CCEB40544FFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{22958135-6A79-445D-88AC-CCEB40544FFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{22958135-6A79-445D-88AC-CCEB40544FFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{22958135-6A79-445D-88AC-CCEB40544FFA}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(NestedProjects) = preSolution
 		{6E58D769-A11D-4D74-AD80-2BD289E7E177} = {2CA15343-B21C-4678-AA1B-523E60BBD17B}
-		{4B611C1E-4494-466A-AA13-BC36C90A9C22} = {4BAC450A-0F7C-42FE-90C8-C5CEB7FFE153}
+		{22958135-6A79-445D-88AC-CCEB40544FFA} = {4BAC450A-0F7C-42FE-90C8-C5CEB7FFE153}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {332CCF9C-BB99-4084-87BF-4E746E132E2E}
diff --git a/appveyor.yml b/appveyor.yml
index 60ba603..dbed349 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,11 +1,10 @@
 configuration: Release
-image: Visual Studio 2017
-pull_requests:
-  - do_not_increment_build_number: true
+image:
+    Visual Studio 2017
 init:
   # Good practise, because Windows line endings are different from Unix/Linux ones
   - cmd: git config --global core.autocrlf true
-before_buid:
+before_build:
   # Display .NET Core version
   - cmd: dotnet --version
   - cmd: dotnet restore ./src/src.csproj --verbosity m
@@ -17,6 +16,9 @@ build:
 
 #tests
 test:
+  assemblies:
+    only:
+        - OpenMovieDatabase.Client.Test.dll
   # all except categories to test
   categories:
     except:
@@ -26,7 +28,7 @@ test:
 deploy:
     provider: NuGet
     api_key:
-        secure: wO5eiWkOc3xv1qM1mChKx6weYq9h795U6u5NJg6kqwdSgsXZVCXjQJk6G05MuPKC
+        secure: p29F21IZFy2nYYvu4elqX/7wqm4be6J6V0dDdYyGXYCW4BvbGTx0UdIsblkg8/33
     skip_symbols: false
     artifact: /.*\.nupkg/
     on:
diff --git a/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj b/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
index f951400..1aff18d 100644
--- a/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
+++ b/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
@@ -2,6 +2,15 @@
 
   <PropertyGroup>
     <TargetFramework>netstandard1.1</TargetFramework>
+    <Authors>@javnov</Authors>
+    <Company />
+    <PackageId>OpenMovieDatabaseApiClient</PackageId>
+    <Product>OpenMovieDatabaseApiClient</Product>
+    <Description>Open movie databsae api .net client</Description>
+    <PackageProjectUrl>https://github.com/javnov/omdb-api-net-client</PackageProjectUrl>
+    <PackageLicenseUrl>https://github.com/javnov/omdb-api-net-client/blob/master/LICENSE</PackageLicenseUrl>
+    <RepositoryUrl>https://github.com/javnov/omdb-api-net-client</RepositoryUrl>
+    <PackageTags>omdb,omdb-api,javnov</PackageTags>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/test/OpenMovieDatabase.Client.Test/OpenMovieDatabase.Client.Test.csproj b/test/OpenMovieDatabase.Client.Test/OpenMovieDatabase.Client.Test.csproj
index 4d1ad57..7c9888c 100644
--- a/test/OpenMovieDatabase.Client.Test/OpenMovieDatabase.Client.Test.csproj
+++ b/test/OpenMovieDatabase.Client.Test/OpenMovieDatabase.Client.Test.csproj
@@ -7,21 +7,15 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170628-02" />
-    <PackageReference Include="xunit" Version="2.2.0" />
-    <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
-    <PackageReference Include="Moq" Version="4.8.3" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
     <PackageReference Include="MockHttpClient" Version="1.0.0" />
+    <PackageReference Include="xunit" Version="2.3.1" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
+    <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
   </ItemGroup>
 
   <ItemGroup>
     <ProjectReference Include="..\..\src\OpenMovieDatabase.Client\OpenMovieDatabase.Client.csproj" />
   </ItemGroup>
-  <ItemGroup>
-    <Compile Remove="Properties\AssemblyInfo.cs" />
-    <Compile Remove="UnitTest1.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <Folder Include="Integration\" />
-  </ItemGroup>
+
 </Project>

From ae9eef33cf3eb4e19ccfb4c0b936291ceff019ac Mon Sep 17 00:00:00 2001
From: Javier Novoa <javier.novoa@outlook.com>
Date: Fri, 29 Jun 2018 20:33:46 -0500
Subject: [PATCH 5/7] Fix appveyor file

---
 appveyor.yml | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/appveyor.yml b/appveyor.yml
index dbed349..f5c7344 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -7,7 +7,15 @@ init:
 before_build:
   # Display .NET Core version
   - cmd: dotnet --version
-  - cmd: dotnet restore ./src/src.csproj --verbosity m
+  - cmd: dotnet restore ./OpenMovieDatabaseNetClient.sln --verbosity m
+ dotnet_csproj:
+  patch: true
+  file: '**\*.csproj'
+  version: '{version}'
+  package_version: '{version}'
+  assembly_version: '{version}'
+  file_version: '{version}'
+  informational_version: '{version}'
 build:
   project: OpenMovieDatabaseNetClient.sln
   verbosity: normal

From 5c4d94a17311615c2dd9ef32c6653be1f379c90e Mon Sep 17 00:00:00 2001
From: Javier Novoa <javier.novoa@outlook.com>
Date: Fri, 29 Jun 2018 20:37:34 -0500
Subject: [PATCH 6/7] Fix appveyor file

---
 appveyor.yml | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/appveyor.yml b/appveyor.yml
index f5c7344..0793718 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -8,14 +8,14 @@ before_build:
   # Display .NET Core version
   - cmd: dotnet --version
   - cmd: dotnet restore ./OpenMovieDatabaseNetClient.sln --verbosity m
- dotnet_csproj:
-  patch: true
-  file: '**\*.csproj'
-  version: '{version}'
-  package_version: '{version}'
-  assembly_version: '{version}'
-  file_version: '{version}'
-  informational_version: '{version}'
+dotnet_csproj:
+    patch: true
+    file: '\src\**\*.csproj'
+    version: '{version}'
+    package_version: '{version}'
+    assembly_version: '{version}'
+    file_version: '{version}'
+    informational_version: '{version}'
 build:
   project: OpenMovieDatabaseNetClient.sln
   verbosity: normal

From 99fd2a8973ac2b55351e0a4f4ce3e37b85754ddd Mon Sep 17 00:00:00 2001
From: Nelson Javier Novoa Tellez <javier.novoa@outlook.com>
Date: Wed, 24 Oct 2018 12:42:54 -0500
Subject: [PATCH 7/7] Parse years like "2013-" to an integer array

---
 src/OpenMovieDatabase.Client/BasicResponse.cs |  2 +-
 .../Internal/InternalSearchItem.cs            |  6 +--
 .../Internal/YearJsonConverter.cs             | 46 +++++++++++++++++++
 .../OpenMovieDatabase.Client.csproj           |  1 -
 .../OpenMovieDatabaseClientIntegrationTest.cs |  6 +--
 .../OpenMovieDatabaseClientTest.cs            |  1 +
 6 files changed, 54 insertions(+), 8 deletions(-)
 create mode 100644 src/OpenMovieDatabase.Client/Internal/YearJsonConverter.cs

diff --git a/src/OpenMovieDatabase.Client/BasicResponse.cs b/src/OpenMovieDatabase.Client/BasicResponse.cs
index c73aa37..de2b372 100644
--- a/src/OpenMovieDatabase.Client/BasicResponse.cs
+++ b/src/OpenMovieDatabase.Client/BasicResponse.cs
@@ -5,7 +5,7 @@ namespace OpenMovieDatabase.Client
     public class BasicResponse
     {
         public string Title { get; }
-        public int Year { get; }
+        public int?[] Year { get; }
         public string ImdbID { get; }
         public ItemType Type { get; }
         public Uri Poster { get; }
diff --git a/src/OpenMovieDatabase.Client/Internal/InternalSearchItem.cs b/src/OpenMovieDatabase.Client/Internal/InternalSearchItem.cs
index 7408b98..b6e6a4b 100644
--- a/src/OpenMovieDatabase.Client/Internal/InternalSearchItem.cs
+++ b/src/OpenMovieDatabase.Client/Internal/InternalSearchItem.cs
@@ -1,5 +1,4 @@
-﻿using System;
-using Newtonsoft.Json;
+﻿using Newtonsoft.Json;
 
 namespace OpenMovieDatabase.Client.Internal
 {
@@ -9,7 +8,8 @@ internal class InternalSearchItem
         internal string Title { get; set; }
 
         [JsonProperty]
-        internal int Year { get; set; }
+        [JsonConverter(typeof(YearJsonConverter))]
+        internal int?[] Year { get; set; }
 
         [JsonProperty]
         internal string Rated { get; set; }
diff --git a/src/OpenMovieDatabase.Client/Internal/YearJsonConverter.cs b/src/OpenMovieDatabase.Client/Internal/YearJsonConverter.cs
new file mode 100644
index 0000000..71708b5
--- /dev/null
+++ b/src/OpenMovieDatabase.Client/Internal/YearJsonConverter.cs
@@ -0,0 +1,46 @@
+﻿using Newtonsoft.Json;
+using System;
+using System.Linq;
+
+namespace OpenMovieDatabase.Client.Internal
+{
+    internal class YearJsonConverter : JsonConverter
+    {
+        public override bool CanConvert(Type objectType)
+        {
+            return objectType == typeof(int[]);
+        }
+
+        public override bool CanRead => true;
+        public override bool CanWrite => false;
+
+        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+        {
+            var value = (string)reader.Value;
+
+            if (string.IsNullOrEmpty(value))
+                return null;
+
+            var values = value.Split('-', '–');
+            if (values.Length > 2)
+                return null;
+
+            return values.Select(ParseValue).ToArray();
+        }
+
+        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+        {
+        }
+
+        private static int? ParseValue(string value)
+        {
+            if (string.IsNullOrEmpty(value))
+                return null;
+
+            if (int.TryParse(value, out int parsedValue))
+                return parsedValue;
+
+            return null;
+        }
+    }
+}
diff --git a/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj b/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
index 1aff18d..db6d25b 100644
--- a/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
+++ b/src/OpenMovieDatabase.Client/OpenMovieDatabase.Client.csproj
@@ -14,7 +14,6 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <Folder Include="Internal\" />
     <Folder Include="Properties\" />
   </ItemGroup>
   <ItemGroup>
diff --git a/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs b/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs
index b2228c6..93c49b7 100644
--- a/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs
+++ b/test/OpenMovieDatabase.Client.Test/Integration/OpenMovieDatabaseClientIntegrationTest.cs
@@ -22,7 +22,7 @@ public OpenMovieDatabaseClientIntegrationTest()
              var httpClient = new HttpClient(handler);
 
             //I'm using the same api key that http://www.omdbapi.com this could be stop working any moment
-            _sut = new OpenMovieDatabaseClient("PlzBanMe", httpClient);
+            _sut = new OpenMovieDatabaseClient("BanMePlz", httpClient);
         }
 
         [Fact]
@@ -59,7 +59,7 @@ public async Task SearchAsyncThrowsError()
         }
 
         [Fact]
-        //[Fact(Skip = "Integration test")]
+        [Trait("Category", "Integration")]
         public async Task GetByIdOrTitleAsync()
         {
             var request = new GetByIdOrTitleRequest
@@ -85,7 +85,7 @@ public async Task GetByIdOrTitleAsync()
         }
 
         [Fact]
-        //[Fact(Skip = "Integration test")]
+        [Trait("Category", "Integration")]
         public async Task GetByIdOrTitleAsyncThrowsError()
         {
             var request = new GetByIdOrTitleRequest
diff --git a/test/OpenMovieDatabase.Client.Test/OpenMovieDatabaseClientTest.cs b/test/OpenMovieDatabase.Client.Test/OpenMovieDatabaseClientTest.cs
index cfa4811..580ea07 100644
--- a/test/OpenMovieDatabase.Client.Test/OpenMovieDatabaseClientTest.cs
+++ b/test/OpenMovieDatabase.Client.Test/OpenMovieDatabaseClientTest.cs
@@ -19,6 +19,7 @@ public void ShouldThrowWhenApiKeyIsNullOrEmptyString(string apiKey)
                 Assert.Throws<ArgumentNullException>(() => new OpenMovieDatabaseClient(apiKey, null));
             }
 
+            [Fact]
             public void ShouldThrowWhenHttpClientIsNull()
             {
                 Assert.Throws<ArgumentNullException>(() => new OpenMovieDatabaseClient("api-key", null));
