Skip to content

Commit

Permalink
Merge branch 'feature/multiple_devices_per_participant' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Jericho committed Feb 4, 2022
2 parents 263c31e + da40bd4 commit 7f0f1a5
Show file tree
Hide file tree
Showing 7 changed files with 357 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Source/ZoomNet.UnitTests/Extensions/Internal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace ZoomNet.UnitTests.Utilities
{
public class InternalTests
public class InternalExtensionsTests
{
[Fact]
public void GetProperty_when_property_is_present_and_throwIfMissing_is_true()
Expand Down
61 changes: 61 additions & 0 deletions Source/ZoomNet.UnitTests/Models/DashboardParticipant.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Newtonsoft.Json;
using Shouldly;
using Xunit;
using ZoomNet.Models;

namespace StrongGrid.UnitTests.Resources
{
public class DashboardParticipantTests
{
#region FIELDS

internal const string SINGLE_DASHBOARDPARTICIPANT_JSON = @"{
'id': 'd52f19c548b88490b5d16fcbd38',
'user_id': '32dsfsd4g5gd',
'user_name': 'dojo',
'device': 'Unknown',
'ip_address': '127.0.0.1',
'location': 'New York',
'network_type': 'Wired',
'microphone': 'Plantronics BT600',
'camera': 'FaceTime HD Camera',
'speaker': 'Plantronics BT600',
'data_center': 'SC',
'full_data_center': 'United States;United States (US03_SC CRC)',
'connection_type': 'P2P',
'join_time': '2019-09-07T13:15:02.837Z',
'leave_time': '2019-09-07T13:15:09.837Z',
'share_application': false,
'share_desktop': true,
'share_whiteboard': true,
'recording': false,
'status': 'in_waiting_room',
'pc_name': 'dojo\'s pc',
'domain': 'Dojo-workspace',
'mac_addr': ' 00:0a:95:9d:68:16',
'harddisk_id': 'sed proident in',
'version': '4.4.55383.0716',
'leave_reason': 'Dojo left the meeting.<br>Reason: Host ended the meeting.',
'sip_uri': 'sip:[email protected]:11029',
'from_sip_uri': 'sip:[email protected]:11029',
'role': 'panelist'
}";

#endregion

[Fact]
public void Parse_json()
{
// Arrange

// Act
var result = JsonConvert.DeserializeObject<DashboardParticipant>(SINGLE_DASHBOARDPARTICIPANT_JSON);

// Assert
result.ShouldNotBeNull();
result.Devices.ShouldNotBeNull();
result.Devices.Length.ShouldBe(1);
result.Devices[0].ShouldBe(ParticipantDevice.Unknown);
}
}
}
147 changes: 147 additions & 0 deletions Source/ZoomNet.UnitTests/Utilities/ParticipantDeviceConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
using Newtonsoft.Json;
using Shouldly;
using System;
using System.IO;
using System.Text;
using Xunit;
using ZoomNet.Models;
using ZoomNet.Utilities;

namespace StrongGrid.UnitTests.Utilities
{
public class ParticipantDeviceConverterTests
{
[Fact]
public void Properties()
{
// Act
var converter = new ParticipantDeviceConverter();

// Assert
converter.CanRead.ShouldBeTrue();
converter.CanWrite.ShouldBeTrue();
}

[Fact]
public void CanConvert()
{
// Act
var converter = new ParticipantDeviceConverter();

// Assert
converter.CanConvert(typeof(string)).ShouldBeTrue();
}

[Fact]
public void Write_single()
{
// Arrange
var sb = new StringBuilder();
var sw = new StringWriter(sb);
var writer = new JsonTextWriter(sw);

var value = new[]
{
ParticipantDevice.Windows
};

var serializer = new JsonSerializer();

var converter = new ParticipantDeviceConverter();

// Act
converter.WriteJson(writer, value, serializer);
var result = sb.ToString();

// Assert
result.ShouldBe("\"Windows\"");
}
[Fact]
public void Write_multiple()
{
// Arrange
var sb = new StringBuilder();
var sw = new StringWriter(sb);
var writer = new JsonTextWriter(sw);

var value = new[]
{
ParticipantDevice.Unknown,
ParticipantDevice.Phone
};

var serializer = new JsonSerializer();

var converter = new ParticipantDeviceConverter();

// Act
converter.WriteJson(writer, value, serializer);
var result = sb.ToString();

// Assert
result.ShouldBe("\"Unknown + Phone\"");
}

[Theory]
[InlineDataAttribute("", ParticipantDevice.Unknown)]
[InlineDataAttribute("Unknown", ParticipantDevice.Unknown)]
[InlineDataAttribute("Android", ParticipantDevice.Android)]
[InlineDataAttribute("Phone", ParticipantDevice.Phone)]
[InlineDataAttribute("iOs", ParticipantDevice.IOS)]
[InlineDataAttribute("H.323/SIP", ParticipantDevice.Sip)]
[InlineDataAttribute("Windows", ParticipantDevice.Windows)]
public void Read_single(string value, ParticipantDevice expectedValue)
{
// Arrange
var json = $"'{value}'";

var textReader = new StringReader(json);
var jsonReader = new JsonTextReader(textReader);
var objectType = (Type)null;
var existingValue = (object)null;
var serializer = new JsonSerializer();

var converter = new ParticipantDeviceConverter();

// Act
jsonReader.Read();
var result = converter.ReadJson(jsonReader, objectType, existingValue, serializer);

// Assert
result.ShouldNotBeNull();
result.ShouldBeOfType<ParticipantDevice[]>();

var resultAsArray = (ParticipantDevice[])result;
resultAsArray.Length.ShouldBe(1);
resultAsArray[0].ShouldBe(expectedValue);
}

[Fact]
public void Read_multiple()
{
// Arrange
var json = "'Unknown + Phone'";

var textReader = new StringReader(json);
var jsonReader = new JsonTextReader(textReader);
var objectType = (Type)null;
var existingValue = (object)null;
var serializer = new JsonSerializer();

var converter = new ParticipantDeviceConverter();

// Act
jsonReader.Read();
var result = converter.ReadJson(jsonReader, objectType, existingValue, serializer);

// Assert
result.ShouldNotBeNull();
result.ShouldBeOfType<ParticipantDevice[]>();

var resultAsArray = (ParticipantDevice[])result;
resultAsArray.Length.ShouldBe(2);
resultAsArray[0].ShouldBe(ParticipantDevice.Unknown);
resultAsArray[1].ShouldBe(ParticipantDevice.Phone);
}
}
}
45 changes: 45 additions & 0 deletions Source/ZoomNet/Extensions/Internal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
using Pathoschild.Http.Client;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -712,6 +714,49 @@ internal static void Replace<T>(this ICollection<T> collection, T oldValue, T ne
}
}

/// <summary>Convert an enum to its string representation.</summary>
/// <typeparam name="T">The enum type.</typeparam>
/// <param name="enumValue">The value.</param>
/// <returns>The string representation of the enum value.</returns>
/// <remarks>Inspired by: https://stackoverflow.com/questions/10418651/using-enummemberattribute-and-doing-automatic-string-conversions .</remarks>
internal static string ToEnumString<T>(this T enumValue)
where T : Enum
{
var enumMemberAttribute = enumValue.GetAttributeOfType<EnumMemberAttribute>();
if (enumMemberAttribute != null) return enumMemberAttribute.Value;

var descriptionAttribute = enumValue.GetAttributeOfType<DescriptionAttribute>();
if (descriptionAttribute != null) return descriptionAttribute.Description;

return enumValue.ToString();
}

/// <summary>Parses a string into its corresponding enum value.</summary>
/// <typeparam name="T">The enum type.</typeparam>
/// <param name="str">The string value.</param>
/// <returns>The enum representation of the string value.</returns>
/// <remarks>Inspired by: https://stackoverflow.com/questions/10418651/using-enummemberattribute-and-doing-automatic-string-conversions .</remarks>
internal static T ToEnum<T>(this string str)
where T : Enum
{
var enumType = typeof(T);
foreach (var name in Enum.GetNames(enumType))
{
var customAttributes = enumType.GetField(name).GetCustomAttributes(true);

// See if there's a matching 'EnumMember' attribute
if (customAttributes.OfType<EnumMemberAttribute>().Any(attribute => string.Equals(attribute.Value, str, StringComparison.OrdinalIgnoreCase))) return (T)Enum.Parse(enumType, name);

// See if there's a matching 'Description' attribute
if (customAttributes.OfType<DescriptionAttribute>().Any(attribute => string.Equals(attribute.Description, str, StringComparison.OrdinalIgnoreCase))) return (T)Enum.Parse(enumType, name);

// See if the value matches the name
if (string.Equals(name, str, StringComparison.OrdinalIgnoreCase)) return (T)Enum.Parse(enumType, name);
}

throw new ArgumentException($"There is no value in the {enumType.Name} enum that corresponds to '{str}'.");
}

/// <summary>Asynchronously converts the JSON encoded content and convert it to an object of the desired type.</summary>
/// <typeparam name="T">The response model to deserialize into.</typeparam>
/// <param name="httpContent">The content.</param>
Expand Down
8 changes: 5 additions & 3 deletions Source/ZoomNet/Models/DashboardParticipant.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Newtonsoft.Json;
using System;
using ZoomNet.Utilities;

namespace ZoomNet.Models
{
Expand Down Expand Up @@ -38,13 +39,14 @@ public class DashboardParticipant
public string UserName { get; set; }

/// <summary>
/// Gets or sets the type of device using which the participant joined the meeting.
/// Gets or sets the device(s) used by the participant to join the meeting.
/// </summary>
/// <value>
/// The type of device using which the participant joined the meeting.
/// The type of device used by the participant to join the meeting.
/// </value>
[JsonProperty(PropertyName = "device")]
public ParticipantDevice Device { get; set; }
[JsonConverter(typeof(ParticipantDeviceConverter))]
public ParticipantDevice[] Devices { get; set; }

/// <summary>
/// Gets or sets the participant’s IP address.
Expand Down
8 changes: 4 additions & 4 deletions Source/ZoomNet/Models/ParticipantDevice.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Runtime.Serialization;
using ZoomNet.Utilities;

namespace ZoomNet.Models
{
/// <summary>
/// Enumeration to indicate the type of device a participant used to join a meeting.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
[JsonConverter(typeof(ParticipantDeviceConverter))]
public enum ParticipantDevice
{
/// <summary>
/// Unknown
/// Unknown.
/// </summary>
[EnumMember(Value = "")]
[EnumMember(Value = "Unknown")]
Unknown,

/// <summary>
Expand Down
Loading

0 comments on commit 7f0f1a5

Please sign in to comment.