Skip to content

Commit fa8b4f0

Browse files
authored
Merge pull request #12 from xboxoneresearch/feat/version_update_check
Check for app and firmware update.
2 parents f7db088 + 8b00b3f commit fa8b4f0

14 files changed

Lines changed: 382 additions & 12 deletions

.github/workflows/build.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ jobs:
7070
- name: Restore dependencies
7171
run: dotnet restore
7272

73+
- name: Test
74+
shell: bash
75+
run: |
76+
dotnet test --no-restore --configuration ${{ matrix.configuration }}
77+
7378
- name: Build
7479
shell: bash
7580
run: |

PostCodeGUI.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ VisualStudioVersion = 17.0.31903.59
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PostCodeSerialMonitor", "PostCodeSerialMonitor\PostCodeSerialMonitor.csproj", "{EBB8E46D-05A6-46CF-9C53-7DF64086F492}"
77
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PostCodeSerialMonitor.Tests", "PostCodeSerialMonitor.Tests\PostCodeSerialMonitor.Tests.csproj", "{D629C06E-3323-47AF-83C1-B7A21D978ED2}"
9+
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1012
Debug|Any CPU = Debug|Any CPU
@@ -27,6 +29,18 @@ Global
2729
{EBB8E46D-05A6-46CF-9C53-7DF64086F492}.Release|x64.Build.0 = Release|Any CPU
2830
{EBB8E46D-05A6-46CF-9C53-7DF64086F492}.Release|x86.ActiveCfg = Release|Any CPU
2931
{EBB8E46D-05A6-46CF-9C53-7DF64086F492}.Release|x86.Build.0 = Release|Any CPU
32+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Debug|Any CPU.Build.0 = Debug|Any CPU
34+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Debug|x64.ActiveCfg = Debug|Any CPU
35+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Debug|x64.Build.0 = Debug|Any CPU
36+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Debug|x86.ActiveCfg = Debug|Any CPU
37+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Debug|x86.Build.0 = Debug|Any CPU
38+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU
39+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Release|Any CPU.Build.0 = Release|Any CPU
40+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Release|x64.ActiveCfg = Release|Any CPU
41+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Release|x64.Build.0 = Release|Any CPU
42+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Release|x86.ActiveCfg = Release|Any CPU
43+
{D629C06E-3323-47AF-83C1-B7A21D978ED2}.Release|x86.Build.0 = Release|Any CPU
3044
EndGlobalSection
3145
GlobalSection(SolutionProperties) = preSolution
3246
HideSolutionNode = FALSE

PostCodeSerialMonitor.Tests/PostCodeSerialMonitor.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
<TargetFramework>net9.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
7+
<IsTestProject>true</IsTestProject>
78
<IsPackable>false</IsPackable>
9+
<IsPublishable>false</IsPublishable>
810
</PropertyGroup>
911

1012
<ItemGroup>
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using System.Collections;
2+
using PostCodeSerialMonitor.Models;
3+
4+
namespace PostCodeSerialMonitor.Tests;
5+
public class SemanticVersionTestDataGenerator : IEnumerable<object[]>
6+
{
7+
private readonly List<object[]> _data = new List<object[]>
8+
{
9+
new object[] {"0.2.0.0", "0.2.1.0", true},
10+
new object[] {"0.2.0.0", "0.2.10.0", true},
11+
new object[] {"0.2.0.0", "0.2.0.1", true},
12+
new object[] {"0.2.0.0", "0.3.0", true},
13+
new object[] {"0.2.0.0", "0.1.99", false},
14+
new object[] {"0.2.0.0", "0.1.33.0", false},
15+
new object[] {"0.3.0", "0.3.1", true},
16+
new object[] {"0.3.1.0", "0.3.11.0", true},
17+
new object[] {"0.3.2.0", "0.3.20.0", true},
18+
new object[] {"0.3.11.0", "0.3.1.0", false},
19+
20+
new object[] {"1.0.0", "1.0.1", true},
21+
new object[] {"1.0.0", "1.1.0", true},
22+
new object[] {"1.0.0", "2.0.0", true},
23+
new object[] {"2.0.0", "1.9.9", false},
24+
new object[] {"1.2.3", "1.2.4", true},
25+
new object[] {"1.2.3", "1.3.0", true},
26+
new object[] {"1.2.3", "2.0.0", true},
27+
new object[] {"1.2.3", "1.2.3", false},
28+
new object[] {"10.0.0", "9.99.99", false},
29+
new object[] {"0.0.1", "0.0.2", true},
30+
new object[] {"0.0.1", "0.1.0", true},
31+
new object[] {"0.0.1", "1.0.0", true},
32+
33+
new object[] {"v0.2.0.0", "v0.2.1.0", true},
34+
new object[] {"v0.2.0.0", "0.2.1.0", true},
35+
new object[] {"0.2.0.0", "v0.2.1.0", true},
36+
new object[] {"v1.0.0", "v1.0.1", true},
37+
new object[] {"v1.0.0", "1.0.1", true},
38+
new object[] {"1.0.0", "v1.0.1", true},
39+
new object[] {"v2.3.4", "v2.3.5", true},
40+
new object[] {"v2.3.4", "2.3.5", true},
41+
new object[] {"2.3.4", "v2.3.5", true},
42+
new object[] {"v10.20.30", "v10.20.31", true},
43+
new object[] {"v10.20.30", "10.20.31", true},
44+
new object[] {"10.20.30", "v10.20.31", true},
45+
46+
new object[] {"v0.0.1", "v0.0.2", true},
47+
new object[] {"v0.0.1", "0.0.2", true},
48+
new object[] {"0.0.1", "v0.0.2", true},
49+
new object[] {"v1.2.3", "v1.2.3", false},
50+
new object[] {"v1.2.3", "1.2.3", false},
51+
new object[] {"1.2.3", "v1.2.3", false},
52+
53+
new object[] {"0.1.0", "v0.2.0", true},
54+
new object[] {"v0.1.0", "0.2.0", true},
55+
new object[] {"0.1.0.0", "v0.2.0", true},
56+
new object[] {"v0.1.0.0", "0.2.0", true},
57+
new object[] {"1.0.0.0", "v1.1.0", true},
58+
new object[] {"v1.0.0.0", "1.1.0", true},
59+
60+
new object[] {"0.9.9.9", "v1.0.0.0", true},
61+
new object[] {"v0.9.9.9", "1.0.0.0", true},
62+
new object[] {"1.99.99.99", "v2.0.0.0", true},
63+
new object[] {"v1.99.99.99", "2.0.0.0", true},
64+
new object[] {"0.0.0.1", "v0.0.0.2", true},
65+
new object[] {"v0.0.0.1", "0.0.0", false},
66+
};
67+
68+
public IEnumerator<object[]> GetEnumerator() => _data.GetEnumerator();
69+
70+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
71+
}
72+
73+
public class SemanticVersionTests
74+
{
75+
[Fact]
76+
public void TestParsing()
77+
{
78+
Assert.Equal([0, 1, 2, 3], new SemanticVersion("v0.1.2.3").VersionParts);
79+
Assert.Equal([0, 1, 2, 3], new SemanticVersion("0.1.2.3").VersionParts);
80+
Assert.Equal([0, 1, 2, 0], new SemanticVersion("v0.1.2").VersionParts);
81+
Assert.Equal([0, 1, 2, 0], new SemanticVersion("0.1.2").VersionParts);
82+
}
83+
84+
[Theory]
85+
[ClassData(typeof(SemanticVersionTestDataGenerator))]
86+
public void TestComparison(string localVersion, string remoteVersion, bool isNewer)
87+
{
88+
var local = new SemanticVersion(localVersion);
89+
var remote = new SemanticVersion(remoteVersion);
90+
91+
Assert.Equal(isNewer, remote > local);
92+
}
93+
}

PostCodeSerialMonitor.Tests/SerialDecoderTests.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.Extensions.Logging;
77
using Microsoft.Extensions.Options;
88
using System.Text.Json;
9+
using Moq;
910

1011
namespace PostCodeSerialMonitor.Tests;
1112
public class TestDataGenerator : IEnumerable<object[]>
@@ -41,14 +42,17 @@ public SerialDecoderTests()
4142

4243
// Create configuration
4344
var config = new AppConfiguration();
44-
var options = Options.Create(config);
45+
var optionsMonitor = new Mock<IOptionsMonitor<AppConfiguration>>();
46+
optionsMonitor.Setup(m => m.CurrentValue).Returns(config);
4547

4648
// Create logger factory
4749
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
50+
var loggerMeta = new Mock<ILogger<MetaDefinitionService>>().Object;
51+
var loggerDecoder = new Mock<ILogger<SerialLineDecoder>>().Object;
4852

4953
// Create configuration service
5054
var configService = new ConfigurationService(
51-
options,
55+
optionsMonitor.Object,
5256
loggerFactory.CreateLogger<ConfigurationService>(),
5357
Path.GetDirectoryName(_testDataPath) ?? "."
5458
);
@@ -69,17 +73,17 @@ public SerialDecoderTests()
6973
);
7074

7175
// Create MetaDefinitionService
72-
var metaDefinitionService = new MetaDefinitionService(configService, metaUpdateService);
76+
var metaDefinitionService = new MetaDefinitionService(configService, metaUpdateService, loggerMeta);
7377
metaDefinitionService.RefreshMetaDefinitionsAsync().GetAwaiter().GetResult();
7478

75-
_decoder = new SerialLineDecoder(metaDefinitionService);
79+
_decoder = new SerialLineDecoder(metaDefinitionService, loggerDecoder);
7680
}
7781

7882
[Theory]
7983
[ClassData(typeof(TestDataGenerator))]
8084
public void TestDecoding(string input, DecodedCode expected)
8185
{
82-
var result = _decoder.DecodeLine(input, ConsoleType.XboxOne);
86+
var result = _decoder.DecodeLine(input, ConsoleType.XboxOnePhat);
8387
Assert.NotNull(result);
8488
Assert.Equal(expected.Flavor, result.Flavor);
8589
Assert.Equal(expected.Index, result.Index);

PostCodeSerialMonitor/Assets/Resources.Designer.cs

Lines changed: 37 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PostCodeSerialMonitor/Assets/Resources.pt-BR.resx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,14 @@
169169
<value>Falha ao baixar MetaDefinition de {0}</value>
170170
<comment>In Services/MetaUpdateService.cs</comment>
171171
</data>
172+
<data name="FailedDeserializingReleaseDefinition" xml:space="preserve">
173+
<value>Falha ao deserializar ReleaseDefinition</value>
174+
<comment>In Services/MetaUpdateService.cs</comment>
175+
</data>
176+
<data name="FailedDownloadReleaseDefinition" xml:space="preserve">
177+
<value>Falha ao baixar o último lançamento de {0}</value>
178+
<comment>In Services/MetaUpdateService.cs</comment>
179+
</data>
172180
<data name="DecoderIgnoringLine" xml:space="preserve">
173181
<value>Decodificador: Ignorando linha {0}</value>
174182
<comment>In Services/SerialLineDecoder.cs</comment>
@@ -225,6 +233,14 @@
225233
<value>Falha ao ataulizar o metadata</value>
226234
<comment>In ViewModels/MainWindowViewModel.cs</comment>
227235
</data>
236+
<data name="NewAppReleaseAvailable" xml:space="preserve">
237+
<value>Uma nova versão do aplicativo está disponível em {0}.</value>
238+
<comment>In ViewModels/MainWindowViewModel.cs</comment>
239+
</data>
240+
<data name="NewFirmwareReleaseAvailable" xml:space="preserve">
241+
<value>Uma nova versão do firmware está disponível em {0}.</value>
242+
<comment>In ViewModels/MainWindowViewModel.cs</comment>
243+
</data>
228244
<data name="Error" xml:space="preserve">
229245
<value>Erro</value>
230246
<comment>In ViewModels/MainWindowViewModel.cs</comment>

PostCodeSerialMonitor/Assets/Resources.resx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,14 @@
169169
<value>Failed to download MetaDefinition from {0}</value>
170170
<comment>In Services/MetaUpdateService.cs</comment>
171171
</data>
172+
<data name="FailedDeserializingReleaseDefinition" xml:space="preserve">
173+
<value>Failed deserializing ReleaseDefinition</value>
174+
<comment>In Services/MetaUpdateService.cs</comment>
175+
</data>
176+
<data name="FailedDownloadReleaseDefinition" xml:space="preserve">
177+
<value>Failed to download latest release from {0}</value>
178+
<comment>In Services/MetaUpdateService.cs</comment>
179+
</data>
172180
<data name="DecoderIgnoringLine" xml:space="preserve">
173181
<value>Decoder: Ignoring line {0}</value>
174182
<comment>In Services/SerialLineDecoder.cs</comment>
@@ -225,6 +233,14 @@
225233
<value>Failed to update metadata</value>
226234
<comment>In ViewModels/MainWindowViewModel.cs</comment>
227235
</data>
236+
<data name="NewAppReleaseAvailable" xml:space="preserve">
237+
<value>A new app release is available at {0}.</value>
238+
<comment>In ViewModels/MainWindowViewModel.cs</comment>
239+
</data>
240+
<data name="NewFirmwareReleaseAvailable" xml:space="preserve">
241+
<value>A new firmware release is available at {0}.</value>
242+
<comment>In ViewModels/MainWindowViewModel.cs</comment>
243+
</data>
228244
<data name="Error" xml:space="preserve">
229245
<value>Error</value>
230246
<comment>In ViewModels/MainWindowViewModel.cs</comment>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
namespace PostCodeSerialMonitor.Models;
2+
public class ReleaseDefinition
3+
{
4+
public string tag_name { get; set; } = string.Empty;
5+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text.RegularExpressions;
6+
7+
namespace PostCodeSerialMonitor.Models;
8+
9+
public partial class SemanticVersion
10+
{
11+
public const int MIN_PARTS = 3;
12+
public const int EXPECTED_PARTS = 4;
13+
public string Version { get; } = string.Empty;
14+
15+
// Format: Major.Minor.Patch.<optional build>
16+
public List<int> VersionParts { get; } = [];
17+
18+
[GeneratedRegex(@"^(?:v)?(\d+)\.(\d+)\.(\d+)\.?(\d+)?", RegexOptions.IgnoreCase | RegexOptions.Compiled, "en-US")]
19+
private static partial Regex VersionPartsRegex();
20+
21+
public SemanticVersion(string version)
22+
{
23+
var match = VersionPartsRegex().Match(version);
24+
25+
VersionParts = match.Groups.Values
26+
// Skip first entry (the full matched string!)
27+
.Skip(1)
28+
.Select(x => x.Success ? int.Parse(x.Value) : 0)
29+
.ToList();
30+
31+
if (VersionParts.Count < MIN_PARTS)
32+
{
33+
throw new InvalidDataException("Expecting at least 3 numbers in SemanticVersion");
34+
}
35+
36+
//Ignore the 'v' at the beginning of the version string
37+
if (version.StartsWith("v"))
38+
{
39+
Version = version.Substring(1);
40+
}
41+
else
42+
{
43+
Version = version;
44+
}
45+
}
46+
47+
/// Override greater-than operator for SemanticVersion
48+
public static bool operator >(SemanticVersion left, SemanticVersion right)
49+
{
50+
for (int i = 0; i < EXPECTED_PARTS; i++)
51+
{
52+
if (left.VersionParts[i] > right.VersionParts[i]) return true;
53+
if (left.VersionParts[i] < right.VersionParts[i]) return false;
54+
}
55+
return false;
56+
}
57+
58+
/// Override less-than operator for SemanticVersion
59+
public static bool operator <(SemanticVersion left, SemanticVersion right)
60+
{
61+
for (int i = 0; i < EXPECTED_PARTS; i++)
62+
{
63+
if (left.VersionParts[i] < right.VersionParts[i]) return true;
64+
if (left.VersionParts[i] > right.VersionParts[i]) return false;
65+
}
66+
return false;
67+
}
68+
}

0 commit comments

Comments
 (0)