Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Device.BatteryLevel is now float
  • Loading branch information
jamescrosswell committed Aug 26, 2024
commit bb54c281e93a7cfe1ea77012febd8a8a4ce0deb7
2 changes: 1 addition & 1 deletion src/Sentry.Maui/Internal/MauiDeviceData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static void ApplyMauiDeviceData(this Device device, IDiagnosticLogger? lo
try
{
var battery = Battery.Default;
device.BatteryLevel ??= battery.ChargeLevel < 0 ? null : (short)(battery.ChargeLevel * 100.0);
device.BatteryLevel ??= battery.ChargeLevel < 0 ? null : (float)(battery.ChargeLevel * 100.0);
device.BatteryStatus ??= battery.State.ToString();
device.IsCharging ??= battery.State switch
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static void ApplyFromSentryAndroidSdk(this Device device, JavaSdk.Protoco
device.Name ??= d.Name;
device.Family ??= d.Family;
device.ModelId ??= d.ModelId;
device.BatteryLevel ??= d.BatteryLevel?.ShortValue();
device.BatteryLevel ??= d.BatteryLevel?.FloatValue();
device.IsCharging ??= d.IsCharging()?.BooleanValue();
device.IsOnline ??= d.IsOnline()?.BooleanValue();
device.Orientation ??= d.Orientation?.ToDeviceOrientation();
Expand Down
14 changes: 4 additions & 10 deletions src/Sentry/Protocol/Device.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ public sealed class Device : ISentryJsonSerializable, ICloneable<Device>, IUpdat
public string? Architecture { get; set; }

/// <summary>
/// If the device has a battery an integer defining the battery level (in the range 0-100).
/// If the device has a battery a number defining the battery level (in the range 0-100).
/// </summary>
public short? BatteryLevel { get; set; }
public float? BatteryLevel { get; set; }

/// <summary>
/// True if the device is charging.
Expand Down Expand Up @@ -426,15 +426,9 @@ public static Device FromJson(JsonElement json)
var model = json.GetPropertyOrNull("model")?.GetString();
var modelId = json.GetPropertyOrNull("model_id")?.GetString();
var architecture = json.GetPropertyOrNull("arch")?.GetString();

// TODO: For next major: Remove this and change BatteryLevel from short to float
// The Java and Cocoa SDK report the battery as `float`
// Cocoa https://github.com/getsentry/sentry-cocoa/blob/e773cad622b86735f1673368414009475e4119fd/Sources/Sentry/include/SentryUIDeviceWrapper.h#L18
// Java https://github.com/getsentry/sentry-java/blob/25f1ca4e1636a801c17c1662f0145f888550bce8/sentry/src/main/java/io/sentry/protocol/Device.java#L231-L233
var batteryLevel = json.GetPropertyOrNull("battery_level")?.TryGetDouble(out var level) is true
? (short)level
: (short?)null;

? (float)level
: (float?)null;
var isCharging = json.GetPropertyOrNull("charging")?.GetBoolean();
var isOnline = json.GetPropertyOrNull("online")?.GetBoolean();
var orientation = json.GetPropertyOrNull("orientation")?.GetString()?.ParseEnum<DeviceOrientation>();
Expand Down
206 changes: 126 additions & 80 deletions test/Sentry.Tests/Protocol/Context/DeviceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Sentry.Tests.Protocol.Context;
public class DeviceTests
{
private readonly IDiagnosticLogger _testOutputLogger;
private const float Delta = 0.0001f;

public DeviceTests(ITestOutputHelper output)
{
Expand Down Expand Up @@ -116,93 +117,28 @@ public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject()
[Fact]
public void Clone_CopyValues()
{
var sut = new Device
{
Name = "name",
Brand = "brand",
Manufacturer = "manufacturer",
Family = "family",
Model = "Model",
ModelId = "ModelId",
Architecture = "Architecture",
BatteryLevel = 2,
IsCharging = false,
Orientation = DeviceOrientation.Portrait,
Simulator = true,
MemorySize = 3,
FreeMemory = 4,
UsableMemory = 5,
LowMemory = false,
StorageSize = 6,
FreeStorage = 7,
ExternalStorageSize = 8,
ExternalFreeStorage = 9,
ScreenResolution = "1x1",
ScreenDensity = 10,
ScreenDpi = 11,
BootTime = DateTimeOffset.UtcNow,
Timezone = TimeZoneInfo.Utc,
IsOnline = false,
ProcessorCount = 8,
CpuDescription = "Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz",
ProcessorFrequency = 2500,
DeviceType = "Console",
BatteryStatus = "Charging",
DeviceUniqueIdentifier = "d610540d-11d6-4daa-a98c-b71030acae4d",
SupportsVibration = false,
SupportsAccelerometer = true,
SupportsGyroscope = true,
SupportsAudio = true,
SupportsLocationService = true
};
var sut = TestDevice();

var clone = sut.Clone();

Assert.Equal(sut.Name, clone.Name);
Assert.Equal(sut.Family, clone.Family);
Assert.Equal(sut.Brand, clone.Brand);
Assert.Equal(sut.Manufacturer, clone.Manufacturer);
Assert.Equal(sut.Model, clone.Model);
Assert.Equal(sut.ModelId, clone.ModelId);
Assert.Equal(sut.Architecture, clone.Architecture);
Assert.Equal(sut.BatteryLevel, clone.BatteryLevel);
Assert.Equal(sut.IsCharging, clone.IsCharging);
Assert.Equal(sut.Orientation, clone.Orientation);
Assert.Equal(sut.Simulator, clone.Simulator);
Assert.Equal(sut.MemorySize, clone.MemorySize);
Assert.Equal(sut.FreeMemory, clone.FreeMemory);
Assert.Equal(sut.LowMemory, clone.LowMemory);
Assert.Equal(sut.UsableMemory, clone.UsableMemory);
Assert.Equal(sut.StorageSize, clone.StorageSize);
Assert.Equal(sut.FreeStorage, clone.FreeStorage);
Assert.Equal(sut.ExternalStorageSize, clone.ExternalStorageSize);
Assert.Equal(sut.ExternalFreeStorage, clone.ExternalFreeStorage);
Assert.Equal(sut.ScreenResolution, clone.ScreenResolution);
Assert.Equal(sut.ScreenDensity, clone.ScreenDensity);
Assert.Equal(sut.ScreenDpi, clone.ScreenDpi);
Assert.Equal(sut.BootTime, clone.BootTime);
Assert.Equal(sut.Timezone, clone.Timezone);
Assert.Equal(sut.IsOnline, clone.IsOnline);
Assert.Equal(sut.ProcessorCount, clone.ProcessorCount);
Assert.Equal(sut.CpuDescription, clone.CpuDescription);
Assert.Equal(sut.ProcessorFrequency, clone.ProcessorFrequency);
Assert.Equal(sut.DeviceType, clone.DeviceType);
Assert.Equal(sut.BatteryStatus, clone.BatteryStatus);
Assert.Equal(sut.DeviceUniqueIdentifier, clone.DeviceUniqueIdentifier);
Assert.Equal(sut.SupportsVibration, clone.SupportsVibration);
Assert.Equal(sut.SupportsAccelerometer, clone.SupportsAccelerometer);
Assert.Equal(sut.SupportsGyroscope, clone.SupportsGyroscope);
Assert.Equal(sut.SupportsAudio, clone.SupportsAudio);
Assert.Equal(sut.SupportsLocationService, clone.SupportsLocationService);
AssertAreEqual(sut, clone);
}

[Theory]
[MemberData(nameof(TestCases))]
public void SerializeObject_TestCase_SerializesAsExpected((Device device, string serialized) @case)
[Fact]
public void WriteTo_FromJson_Symmetric()
{
var actual = @case.device.ToJsonString(_testOutputLogger);
// Arrange
var sut = TestDevice();

Assert.Equal(@case.serialized, actual);
var json = sut.ToJsonString();
using var document = JsonDocument.Parse(json);
var jsonElement = document.RootElement;

// Act
var result = Device.FromJson(jsonElement);

// Assert
AssertAreEqual(result, sut);
}

[Fact]
Expand All @@ -220,6 +156,29 @@ public void FromJson_NonSystemTimeZone_NoException()
device.Timezone?.DisplayName.Should().Be("tz_name");
}

[Fact]
public void FromJson_BatteryLevelFloat()
{
// Arrange
const string json = """{"type":"device","battery_level":1.5}""";

// Act
var device = Json.Parse(json, Device.FromJson);

// Assert
device.BatteryLevel.Should().NotBeNull();
device.BatteryLevel?.Should().BeApproximately(1.5f, Delta);
}

[Theory]
[MemberData(nameof(TestCases))]
public void SerializeObject_TestCase_SerializesAsExpected((Device device, string serialized) @case)
{
var actual = @case.device.ToJsonString(_testOutputLogger);

Assert.Equal(@case.serialized, actual);
}

public static IEnumerable<object[]> TestCases()
{
yield return new object[] { (new Device(), """{"type":"device"}""") };
Expand All @@ -232,6 +191,7 @@ public static IEnumerable<object[]> TestCases()
yield return new object[] { (new Device { ModelId = "some model id" }, """{"type":"device","model_id":"some model id"}""") };
yield return new object[] { (new Device { Architecture = "some arch" }, """{"type":"device","arch":"some arch"}""") };
yield return new object[] { (new Device { BatteryLevel = 1 }, """{"type":"device","battery_level":1}""") };
yield return new object[] { (new Device { BatteryLevel = 1.5f }, """{"type":"device","battery_level":1.5}""") };
yield return new object[] { (new Device { IsCharging = true }, """{"type":"device","charging":true}""") };
yield return new object[] { (new Device { IsOnline = true }, """{"type":"device","online":true}""") };
yield return new object[] { (new Device { Simulator = false }, """{"type":"device","simulator":false}""") };
Expand Down Expand Up @@ -261,4 +221,90 @@ public static IEnumerable<object[]> TestCases()
yield return new object[] { (new Device { SupportsAudio = true }, """{"type":"device","supports_audio":true}""") };
yield return new object[] { (new Device { SupportsLocationService = true }, """{"type":"device","supports_location_service":true}""") };
}

private static Device TestDevice()
{
return new Device
{
Name = "name",
Brand = "brand",
Manufacturer = "manufacturer",
Family = "family",
Model = "Model",
ModelId = "ModelId",
Architecture = "Architecture",
BatteryLevel = 2,
IsCharging = false,
Orientation = DeviceOrientation.Portrait,
Simulator = true,
MemorySize = 3,
FreeMemory = 4,
UsableMemory = 5,
LowMemory = false,
StorageSize = 6,
FreeStorage = 7,
ExternalStorageSize = 8,
ExternalFreeStorage = 9,
ScreenResolution = "1x1",
ScreenDensity = 10,
ScreenDpi = 11,
BootTime = DateTimeOffset.UtcNow,
Timezone = TimeZoneInfo.Utc,
IsOnline = false,
ProcessorCount = 8,
CpuDescription = "Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz",
ProcessorFrequency = 2500,
DeviceType = "Console",
BatteryStatus = "Charging",
DeviceUniqueIdentifier = "d610540d-11d6-4daa-a98c-b71030acae4d",
SupportsVibration = false,
SupportsAccelerometer = true,
SupportsGyroscope = true,
SupportsAudio = true,
SupportsLocationService = true
};
}

private static void AssertAreEqual(Device actual, Device expected)
{
using (new AssertionScope())
{
actual.Name.Should().Be(expected.Name);
actual.Manufacturer.Should().Be(expected.Manufacturer);
actual.Brand.Should().Be(expected.Brand);
actual.Architecture.Should().Be(expected.Architecture);
actual.BatteryLevel.Should().BeApproximately(expected.BatteryLevel, Delta);
actual.IsCharging.Should().Be(expected.IsCharging);
actual.IsOnline.Should().Be(expected.IsOnline);
actual.BootTime.Should().Be(expected.BootTime);
actual.ExternalFreeStorage.Should().Be(expected.ExternalFreeStorage);
actual.ExternalStorageSize.Should().Be(expected.ExternalStorageSize);
actual.ScreenResolution.Should().Be(expected.ScreenResolution);
actual.ScreenDensity.Should().Be(expected.ScreenDensity);
actual.ScreenDpi.Should().Be(expected.ScreenDpi);
actual.Family.Should().Be(expected.Family);
actual.FreeMemory.Should().Be(expected.FreeMemory);
actual.FreeStorage.Should().Be(expected.FreeStorage);
actual.MemorySize.Should().Be(expected.MemorySize);
actual.Model.Should().Be(expected.Model);
actual.ModelId.Should().Be(expected.ModelId);
actual.Orientation.Should().Be(expected.Orientation);
actual.Simulator.Should().Be(expected.Simulator);
actual.StorageSize.Should().Be(expected.StorageSize);
actual.Timezone.Should().Be(expected.Timezone);
actual.UsableMemory.Should().Be(expected.UsableMemory);
actual.LowMemory.Should().Be(expected.LowMemory);
actual.ProcessorCount.Should().Be(expected.ProcessorCount);
actual.CpuDescription.Should().Be(expected.CpuDescription);
actual.ProcessorFrequency.Should().Be(expected.ProcessorFrequency);
actual.SupportsVibration.Should().Be(expected.SupportsVibration);
actual.DeviceType.Should().Be(expected.DeviceType);
actual.BatteryStatus.Should().Be(expected.BatteryStatus);
actual.DeviceUniqueIdentifier.Should().Be(expected.DeviceUniqueIdentifier);
actual.SupportsAccelerometer.Should().Be(expected.SupportsAccelerometer);
actual.SupportsGyroscope.Should().Be(expected.SupportsGyroscope);
actual.SupportsAudio.Should().Be(expected.SupportsAudio);
actual.SupportsLocationService.Should().Be(expected.SupportsLocationService);
}
}
}
Loading