diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d747a535..6982ab8c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,30 +1,25 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" +name: "Code Analysis" on: - push: + push: # The master branch must be analyzed on a new commit branches: [ master ] pull_request: - # The branches below must be a subset of the branches above + # Any PR on master must be analyzed branches: [ master ] - schedule: - - cron: '39 18 * * 0' - workflow_dispatch: + workflow_dispatch: # CodeQL can be triggered manually jobs: - analyze: - name: Analyze - runs-on: [self-hosted, windows-latest] + analyzeQL: + name: Analyze with CodeQL + # runs-on: [windows-latest] # may cause Out of Memory errors + runs-on: [self-hosted] + + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read strategy: fail-fast: false @@ -33,20 +28,91 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.2 + uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} + - name: Setup .NET Core SDK uses: actions/setup-dotnet@v4.0.0 with: - dotnet-version: 7.x - + dotnet-version: ${{vars.DOTNET_VERSION}} + - run: dotnet restore - - run: dotnet build ./FASTER.sln --configuration Debug + + - name: Build Solution + run: dotnet build ./FASTER.sln --configuration Debug + + - name: Execute unit tests + run: dotnet test - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 + + AnalysisSonar: + name: Analyze with SonarCloud + runs-on: windows-latest + permissions: + pull-requests: write # allows SonarCloud to decorate PRs with analysis results + + # steps: # DOES NOT SCAN FOR SOME REASON ? + # - name: Analyze with SonarCloud + + # # You can pin the exact commit or the version. + # uses: SonarSource/sonarcloud-github-action@v3 + # env: + # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + # with: + # # Additional arguments for the SonarScanner CLI + # args: + # -Dsonar.projectKey=Foxlider_FASTER + # -Dsonar.organization=foxlicorp + # projectBaseDir: . + + + steps: + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: 'zulu' # Alternative distribution options are available. + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Cache SonarCloud packages + uses: actions/cache@v4 + with: + path: ~\sonar\cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + - name: Cache SonarCloud scanner + id: cache-sonar-scanner + uses: actions/cache@v4 + with: + path: .\.sonar\scanner + key: ${{ runner.os }}-sonar-scanner + restore-keys: ${{ runner.os }}-sonar-scanner + + - name: Install SonarCloud scanner + if: steps.cache-sonar-scanner.outputs.cache-hit != 'true' + shell: pwsh + run: | + New-Item -Path .\.sonar\scanner -ItemType Directory + dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner + + - name: Build and analyze + env: + GITHUB_TOKEN: ${{ secrets.PR_DECORATION }} # Needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + shell: pwsh + run: | + .\.sonar\scanner\dotnet-sonarscanner begin /k:"Foxlider_FASTER" /o:"foxlicorp" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" + dotnet build + .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" + \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index de9ddbad..3f8f92d5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -16,4 +16,5 @@ jobs: identifier: Foxlider.FASTER installers-regex: 'Release_x64.zip' max-versions-to-keep: 5 - token: ${{ secrets.WINGET_TOKEN }} # Classic Personal Access Token with [public_repo, workflow] scopes \ No newline at end of file + # Classic Personal Access Token with [public_repo, workflow] scopes + token: ${{ secrets.WINGET_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..56808bec --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,212 @@ +name: "Release Generator" + +# after successful analysis on the main branch, a new pre-release is generated +on: + #Makes a Nighly release on a new commit. + workflow_run: + workflows: [Code Analysis] + types: [completed] + branches: [master] + + #Makes a Release on tag + push: + # Sequence of patterns matched against refs/tags + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + workflow_dispatch: # ReleaseGen can be triggered manually + +env: + IS_RELEASE: ${{ github.ref_type == 'tag' }} + ZIP_NAME: ${{ github.ref_type == 'tag' && 'Release_' || 'Release_Nightly_' }} + ZIP_PATH: ${{ github.ref_type == 'tag' && 'FASTER_' || 'FASTER_Nightly_' }} + +jobs: + + # BUILD APP + build: + + strategy: + matrix: + # runtime: [x64, x86] + runtime: [x64] + + runs-on: windows-latest # For a list of available runner types, refer to + # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on + + env: + Configuration: Release + Solution_Name: FASTER # Replace with your solution name, i.e. MyWpfApp.sln. + Test_Project_Path: FASTERTests\FASTERTests.csproj # Replace with the path to your test project, i.e. MyWpfApp.Tests\MyWpfApp.Tests.csproj. + Wap_Project_Directory: FASTER # Replace with the Wap project directory relative to the solution, i.e. MyWpfApp.Package. + Wap_Project_Path: FASTER.App.Package\FASTER.Package.wapproj # Replace with the path to your Wap project, i.e. MyWpf.App.Package\MyWpfApp.Package.wapproj. + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Install the .NET Core workload + - name: Install .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{vars.DOTNET_VERSION}} + + # Execute all unit tests in the solution + - name: Execute unit tests + run: dotnet test + + # Restore the application to populate the obj folder with RuntimeIdentifiers + - name: Restore the application + run: dotnet restore + + # Build + - name: Build the application + run: dotnet build --configuration $env:Configuration -a $env:Runtime ./FASTER/FASTER.csproj + env: + Runtime: ${{ matrix.runtime }} + + # Pub + - name: Publish the application ${{ matrix.runtime }} + run: dotnet publish --configuration $env:Configuration -a $env:Runtime --self-contained true /p:useapphost=true --output .\$env:ZIP_NAME$env:Runtime ./FASTER/FASTER.csproj + env: + Runtime: ${{ matrix.runtime }} + + # Zip the folder + - name: Zip the application folder + run: Compress-Archive -Path .\$env:ZIP_NAME$env:Runtime\* -DestinationPath .\$env:ZIP_NAME$env:Runtime.zip + shell: pwsh + env: + Runtime: ${{ matrix.runtime }} + + # Get version number + - name: get-net-sdk-project-versions-action + uses: kzrnm/get-net-sdk-project-versions-action@v2.0.0 + id: get-version + with: + proj-path: ./FASTER/FASTER.csproj + + # Get Changes between Tags + - name: Generate Changelog + id: get-changes + run: | + Write-Output "::group::Collecting Changes between Tags..." + + # Set options from inputs + $tagPattern = "^v?\d\.\d+([a-zA-Z]|\.\d+([a-zA-Z])?)?" + $linePrefix = "- " + + # Fetch all tags from origin + git fetch origin --tags --force + + # Get tags that match the pattern and sort them using version sorting in reverse + $tags = git tag --sort=committerdate -l | Select-String -Pattern $tagPattern | Sort-Object -Descending || "" + + # Count the found tags + $countTags = ($tags -split "`n").Count + + # Exit with error if no tags are found + if ($tags -eq "" -or $countTags -le 0) { + Write-Output "::error title=no tags found::changes-between-tags action could not find any tags to work with" + exit 1 + } + + # Take the first tag as latestTag + $latestTag = ($tags -split "`n")[0] + + # Get changes for range + # Check if the latest tag is on the last commit + $latestCommit = git rev-parse HEAD + $latestTagCommit = git rev-list -n 1 $latestTag + + if ($latestCommit -eq $latestTagCommit -and $countTags -gt 1) { + # Use the previous tag if the latest tag is on the last commit + $latestTag = ($tags -split "`n")[1] + + } + + $range = "$latestTag" + "..@" + $changes = git log --pretty=reference --no-decorate $range + + + # If set, add a prefix to every commit message + if ($linePrefix) { + $changes = $changes -replace "^(.*)$", "$linePrefix`$1" + } + + # Set outputs + $EOF = (New-Guid).Guid + "changes<<$EOF" >> $env:GITHUB_OUTPUT + $changes >> $env:GITHUB_OUTPUT + "$EOF" >> $env:GITHUB_OUTPUT + "tag=$latestTag" >> $env:GITHUB_OUTPUT + + # Log the results + Write-Output "tag: $latestTag" + Write-Output "changes:" + Write-Output $changes + + # End log grouping + Write-Output "::endgroup::" + shell: pwsh + + # Set Version Number to environment + - name: Set Version + id: set_version + run: | + if ($env:IS_RELEASE -eq "true") { + echo "VERSION=$env:GITHUB_REF" >> $env:GITHUB_ENV + } else { + echo "VERSION=${{ steps.get-version.outputs.version }}" >> $env:GITHUB_ENV + } + shell: pwsh + + #Create Release + - name: Create Release + if: env.IS_RELEASE == 'true' + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: '${{ env.VERSION }}' + release_name: 'Release ${{ env.VERSION }}' + body: | + Changelog since release ${{ steps.get-changes.outputs.tag }} : + --- + ${{ steps.get-changes.outputs.changes }} + --- + draft: false + prerelease: ${{ env.IS_RELEASE == 'false' }} + + # Upload Artifacts + - name: Upload Release Asset + if: env.IS_RELEASE == 'true' + id: upload-release-asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + Runtime: ${{ matrix.runtime }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: .\${{ env.ZIP_NAME}}${{ env.Runtime }}.zip + asset_name: ${{ env.ZIP_NAME}}${{ env.Runtime }}.zip + asset_content_type: application/zip + + # Create Nightly Release + - name: Create Nightly Release + if: env.IS_RELEASE == 'false' + uses: andelf/nightly-release@main + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + Runtime: ${{ matrix.runtime }} + with: + tag_name: nightly + name: 'Nightly Release v${{ env.VERSION }}' + body: | + Changelog since release ${{ steps.get-changes.outputs.tag }} : + --- + ${{ steps.get-changes.outputs.changes }} + --- + prerelease: true + files: .\${{ env.ZIP_NAME}}${{ env.Runtime }}.zip \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e5902522..c19913e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,9 +43,9 @@ For changes that address core functionality or would require breaking changes (e In general, we follow the ["fork-and-pull" Git workflow](https://github.com/susam/gitpr) While a bit different, it is generally the same idea. -1. Fork the repository to your own Github account +1. Fork the repository to your own GitHub account 2. Clone the project to your machine -3. Create a branch locally with a succinct but descriptive name. It is preferred to branch from the current update branch that should be named feature/Update-X.Y +3. Create a branch locally with a succinct but descriptive name. It is preferred to branch from the current update branch that should be named `feature/shortName` 4. Commit changes to the branch 5. Following any formatting and testing guidelines specific to this repo 6. Push changes to your fork diff --git a/FASTER Maintenance/FASTER Maintenance.csproj b/FASTER Maintenance/FASTER Maintenance.csproj index 5bd11581..bf535bb0 100644 --- a/FASTER Maintenance/FASTER Maintenance.csproj +++ b/FASTER Maintenance/FASTER Maintenance.csproj @@ -12,7 +12,6 @@ 512 true false - ..\.sonarlint\foxlider_fastercsharp.ruleset AnyCPU @@ -24,7 +23,6 @@ prompt 4 8 - ..\.sonarlint\foxlider_fastercsharp.ruleset AnyCPU @@ -35,7 +33,6 @@ prompt 4 8 - ..\.sonarlint\foxlider_fastercsharp.ruleset Properties\app.manifest @@ -65,16 +62,8 @@ - - foxlider_fastercsharp.ruleset - - - - SonarLint.xml - - \ No newline at end of file diff --git a/FASTER Maintenance/Program.cs b/FASTER Maintenance/Program.cs index 1c4eb94f..386cc368 100644 --- a/FASTER Maintenance/Program.cs +++ b/FASTER Maintenance/Program.cs @@ -176,7 +176,7 @@ private static void MigrateTo17() } Console.WriteLine($"\tRead config from '{selected}\\user.config'"); - var servers = conf16.UserSettings.Settings.Setting.FirstOrDefault(s => s.Name == "Servers"); + var servers = conf16.UserSettings.Settings.Setting.Find(s => s.Name == "Servers"); conf16.UserSettings.Settings.Setting.Remove(servers); conf17.UserSettings = new Models._17Models.UserSettings { Settings = new Models._17Models.Settings { Setting = conf16.UserSettings.Settings.Setting } }; Console.WriteLine("\tConverted standard values to 1.7"); diff --git a/FASTER.sln b/FASTER.sln index f208b064..3b729fd9 100644 --- a/FASTER.sln +++ b/FASTER.sln @@ -13,7 +13,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .github\workflows\codeql-analysis.yml = .github\workflows\codeql-analysis.yml FASTER_Version.xml = FASTER_Version.xml NuGet.Config = NuGet.Config + .github\workflows\publish.yml = .github\workflows\publish.yml README.md = README.md + .github\workflows\release.yml = .github\workflows\release.yml EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FASTERTests", "FASTERTests\FASTERTests.csproj", "{65FDF864-BF9B-414A-A6E6-3473BCFB62BE}" diff --git a/FASTER/FASTER - Backup.csproj b/FASTER/FASTER - Backup.csproj index ce7aa469..6dd452ef 100644 --- a/FASTER/FASTER - Backup.csproj +++ b/FASTER/FASTER - Backup.csproj @@ -21,7 +21,6 @@ true FASTERKey.snk false - ..\.sonarlint\foxlider_fastercsharp.ruleset false diff --git a/FASTER/FASTER.csproj b/FASTER/FASTER.csproj index 07dda1be..70a663f5 100644 --- a/FASTER/FASTER.csproj +++ b/FASTER/FASTER.csproj @@ -1,90 +1,78 @@ - - WinExe - net7.0-windows - true - true - win-x64 - true - true - false - true - 1.9.5.2 - Keelah Fox - FoxliCorp. - Fox's Arma Server Tool Extended Rewrite - Copyright © 2019 - https://forums.bohemia.net/forums/topic/224359-foxs-arma-server-tool-extended-rewrite-faster/ - https://github.com/Foxlider/FASTER - Resources\FASTER.ico - FASTER.App - Properties\FASTER.manifest - 9.0 - true - FASTERKey.snk - false - ..\.sonarlint\foxlider_fastercsharp.ruleset - false - - - 1701;1702;NU1701;CS8002 - x64 - none - false - True - - - 1701;1702;NU1701;CS8002 - x64 - - - 1701;1702;NU1701;CS8002 - x86 - - - 1701;1702;NU1701;CS8002 - False - + + WinExe + net8.0-windows + enable + enable + true + Resources\FASTER.ico + Properties\FASTER.manifest + True + FASTERKey.snk + Keelah Fox, Jupster, Canno.n + 1.9.6.1 + FoxliCorp. + Fox's Arma Server Tool Extended Rewrite + Copyright © 2019 + https://github.com/Foxlider/FASTER + README.md + https://github.com/Foxlider/FASTER + LICENSE + + true + true + true + false + + + + + portable + 1701;1702;NU1701;CS8002;CS8618;CS8622 + + + + none + 1701;1702;NU1701;CS8002;CS8618;CS8622 + + + + + PreserveNewest + + + + + + + + True + True + Settings.settings + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + - - - - - + + - + - - - + + + - - - PreserveNewest - - - - - - - - True - True - Settings.settings - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - diff --git a/FASTER/Models/ArmaMod.cs b/FASTER/Models/ArmaMod.cs index 23eb5b12..9f3e27a7 100644 --- a/FASTER/Models/ArmaMod.cs +++ b/FASTER/Models/ArmaMod.cs @@ -273,7 +273,7 @@ internal async Task UpdateModAsync() break; case UpdateState.Success: Status = ArmaModStatus.UpToDate; - var nx = new DateTime(1970, 1, 1); + var nx = DateTime.UnixEpoch; var ts = DateTime.UtcNow - nx; LocalLastUpdated = (ulong) ts.TotalSeconds; diff --git a/FASTER/Models/ServerCfg.cs b/FASTER/Models/ServerCfg.cs index d96b2df4..d5f14f39 100644 --- a/FASTER/Models/ServerCfg.cs +++ b/FASTER/Models/ServerCfg.cs @@ -207,7 +207,7 @@ public bool HeadlessClientEnabled { headlessClientEnabled = value; RaisePropertyChanged("HeadlessClientEnabled"); - if (value && !headlessClients.Any(e => e.Length > 0)) + if (value && !headlessClients.Exists(e => e.Length > 0)) { HeadlessClients = "127.0.0.1"; } } } @@ -733,7 +733,7 @@ public List Missions bool isEqual = _missions.Count == value.Count && !( from mission in value - let local = _missions.FirstOrDefault(m => m.Path == mission.Path) + let local = _missions.Find(m => m.Path == mission.Path) where local == null || local.MissionChecked != mission.MissionChecked select mission ).Any(); @@ -932,8 +932,8 @@ public string ProcessFile() + "\r\n" + "\r\n" + "// HEADLESS CLIENT\r\n" - + $"{(headlessClientEnabled && !headlessClients.Any(string.IsNullOrWhiteSpace) ? $"headlessClients[] = { "{\n\t\"" + string.Join("\",\n\t \"", headlessClients) + "\"\n}" };\r\n" : "")}" - + $"{(headlessClientEnabled && !localClient.Any(string.IsNullOrWhiteSpace)? $"localClient[] = { "{\n\t\"" + string.Join("\",\n\t \"", localClient) + "\"\n}" };" : "")}"; + + $"{(headlessClientEnabled && !headlessClients.Exists(string.IsNullOrWhiteSpace) ? $"headlessClients[] = { "{\n\t\"" + string.Join("\",\n\t \"", headlessClients) + "\"\n}" };\r\n" : "")}" + + $"{(headlessClientEnabled && !localClient.Exists(string.IsNullOrWhiteSpace)? $"localClient[] = { "{\n\t\"" + string.Join("\",\n\t \"", localClient) + "\"\n}" };" : "")}"; return output; } diff --git a/FASTER/Models/ServerProfile.cs b/FASTER/Models/ServerProfile.cs index b74a42c5..cb61afae 100644 --- a/FASTER/Models/ServerProfile.cs +++ b/FASTER/Models/ServerProfile.cs @@ -112,7 +112,7 @@ public string Executable } } - public string ArmaPath => Path.GetDirectoryName(_executable); + public string ArmaPath => Path.GetDirectoryName(_executable) ?? string.Empty; public int Port { @@ -447,7 +447,7 @@ public ServerProfile Clone() { p.GenerateNewId(); - if (p.Name.EndsWith(")") && p.Name.Contains('(') && int.TryParse(p.Name.Substring(p.Name.Length - 2, 1), out _)) + if (p.Name.EndsWith(')') && p.Name.Contains('(') && int.TryParse(p.Name.Substring(p.Name.Length - 2, 1), out _)) { var i = p.Name.IndexOf('('); var j = p.Name.Length; diff --git a/FASTER/ViewModel/ModsViewModel.cs b/FASTER/ViewModel/ModsViewModel.cs index 018da622..ee8eced9 100644 --- a/FASTER/ViewModel/ModsViewModel.cs +++ b/FASTER/ViewModel/ModsViewModel.cs @@ -80,9 +80,9 @@ public async Task AddLocalModAsync() return; var oldPaths = new List(); - if (!Path.GetFileName(localPath).StartsWith("@") && Directory.GetDirectories(localPath).Where((file) => Path.GetFileName(file).StartsWith("@")).ToList().Count > 0) + if (!Path.GetFileName(localPath).StartsWith('@') && Directory.GetDirectories(localPath).Where((file) => Path.GetFileName(file).StartsWith('@')).ToList().Count > 0) { - oldPaths = Directory.GetDirectories(localPath).Where((file) => Path.GetFileName(file).StartsWith("@")).ToList(); + oldPaths = Directory.GetDirectories(localPath).Where((file) => Path.GetFileName(file).StartsWith('@')).ToList(); } else { diff --git a/FASTER/ViewModel/ProfileViewModel.cs b/FASTER/ViewModel/ProfileViewModel.cs index 192e2779..bfafd88a 100644 --- a/FASTER/ViewModel/ProfileViewModel.cs +++ b/FASTER/ViewModel/ProfileViewModel.cs @@ -199,7 +199,7 @@ internal void DeleteProfile() { Directory.Delete(Path.Combine(Profile.ArmaPath, "Servers", Profile.Id), true); } Properties.Settings.Default.Profiles.Remove(Profile); Properties.Settings.Default.Save(); - MainWindow.Instance.ContentProfileViews.Remove(MainWindow.Instance.ContentProfileViews.FirstOrDefault(p => p.Profile.Id == Profile.Id)); + MainWindow.Instance.ContentProfileViews.Remove(MainWindow.Instance.ContentProfileViews.Find(p => p.Profile.Id == Profile.Id)); var menuItem = MainWindow.Instance.IServerProfilesMenu.Items.Cast().FirstOrDefault(p => p.Name == Profile.Id); if(menuItem != null) MainWindow.Instance.IServerProfilesMenu.Items.Remove(menuItem); @@ -302,7 +302,7 @@ internal void LoadModsFromFile() List notFound = new(); foreach (var extractedMod in extractedModList) { - var mod = Profile.ProfileMods.FirstOrDefault(m => m.Id == extractedMod.Id || ModUtilities.GetCompareString(extractedMod.Name) == ModUtilities.GetCompareString(m.Name)); + var mod = Profile.ProfileMods.Find(m => m.Id == extractedMod.Id || ModUtilities.GetCompareString(extractedMod.Name) == ModUtilities.GetCompareString(m.Name)); if (mod != null) { mod.ClientSideChecked = true; @@ -396,7 +396,7 @@ internal async Task ClearModKeys() { foreach (var keyFile in Directory.GetFiles(Path.Combine(Profile.ArmaPath, "keys"))) { - if (ignoredKeys.Any(keyFile.Contains)) + if (Array.Exists(ignoredKeys, x => keyFile.Contains(x))) continue; try { @@ -423,7 +423,7 @@ public void LoadData() var modlist = new List(); foreach(var mod in Properties.Settings.Default.armaMods.ArmaMods) { - ProfileMod existingMod = Profile.ProfileMods.FirstOrDefault(m => m.Id == mod.WorkshopId); + ProfileMod existingMod = Profile.ProfileMods.Find(m => m.Id == mod.WorkshopId); if (existingMod == null) { var newProfile = new ProfileMod { Name = mod.Name, Id = mod.WorkshopId, IsLocal = mod.IsLocal}; @@ -465,7 +465,7 @@ internal void LoadMissions() foreach (var mission in newMissions) { - ProfileMission existingMission = Profile.ServerCfg.Missions.FirstOrDefault(m => m.Path == mission); + ProfileMission existingMission = Profile.ServerCfg.Missions.Find(m => m.Path == mission); if (existingMission == null) { var newMission = new ProfileMission { Name = mission.Replace(".pbo", ""), Path = mission }; diff --git a/FASTER/ViewModel/SteamUpdaterViewModel.cs b/FASTER/ViewModel/SteamUpdaterViewModel.cs index 298a9c78..1200fdab 100644 --- a/FASTER/ViewModel/SteamUpdaterViewModel.cs +++ b/FASTER/ViewModel/SteamUpdaterViewModel.cs @@ -12,21 +12,16 @@ using Microsoft.AppCenter.Analytics; -using System; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Configuration; using System.Diagnostics; using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using System.Windows.Threading; namespace FASTER.ViewModel { - public sealed class SteamUpdaterViewModel : INotifyPropertyChanged + public sealed class SteamUpdaterViewModel : INotifyPropertyChanged, IDisposable { public SteamUpdaterViewModel() { @@ -446,7 +441,7 @@ public async Task RunModsUpdater(ObservableCollection mods) { ManifestId manifestId = default; - if(mod.LocalLastUpdated > mod.SteamLastUpdated) + if(mod.LocalLastUpdated > mod.SteamLastUpdated && mod.Size > 0) { mod.Status = ArmaModStatus.UpToDate; Parameters.Output += $"\n Mod{mod.WorkshopId} already up to date. Ignoring..."; @@ -466,6 +461,11 @@ public async Task RunModsUpdater(ObservableCollection mods) var downloadHandler = SteamContentClient.GetPublishedFileDataAsync(mod.WorkshopId, manifestId, tokenSource.Token); DownloadForMultiple(downloadHandler.Result, mod.Path).Wait(); + + mod.Status = ArmaModStatus.UpToDate; + var nx = DateTime.UnixEpoch; + var ts = DateTime.UtcNow - nx; + mod.LocalLastUpdated = (ulong)ts.TotalSeconds; } catch (TaskCanceledException) { @@ -478,18 +478,12 @@ public async Task RunModsUpdater(ObservableCollection mods) mod.Status = ArmaModStatus.NotComplete; Parameters.Output += $"\nError: {ex.Message}{(ex.InnerException != null ? $" Inner Exception: {ex.InnerException.Message}" : "")}"; } - sw.Stop(); - mod.Status = ArmaModStatus.UpToDate; - var nx = new DateTime(1970, 1, 1); - var ts = DateTime.UtcNow - nx; - mod.LocalLastUpdated = (ulong) ts.TotalSeconds; mod.CheckModSize(); Parameters.Output += $"\n Download {mod.WorkshopId} completed, it took {sw.Elapsed.Minutes + sw.Elapsed.Hours*60}m {sw.Elapsed.Seconds}s {sw.Elapsed.Milliseconds}ms"; - }, TaskCreationOptions.LongRunning).ContinueWith((_) => { finished += 1; @@ -510,6 +504,8 @@ public async Task RunModsUpdater(ObservableCollection mods) internal async Task SteamLogin() { + if (tokenSource.IsCancellationRequested) + tokenSource = new CancellationTokenSource(); IsLoggingIn = true; var path = Path.Combine(Path.GetDirectoryName(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath) ?? string.Empty, "sentries"); @@ -530,7 +526,7 @@ internal async Task SteamLogin() Parameters.Output += $"\nConnecting to Steam as {(_steamCredentials.IsAnonymous ? "anonymous" : _steamCredentials.Username)}"; SteamClient.MaximumLogonAttempts = 5; try - { await SteamClient.ConnectAsync(); } + { await SteamClient.ConnectAsync(tokenSource.Token); } catch (SteamClientAlreadyRunningException) { Parameters.Output += $"\nClient already logged in."; @@ -609,8 +605,12 @@ private async Task Download(IDownloadHandler downloadHandler, string targetDir) if (tokenSource.IsCancellationRequested) tokenSource = new CancellationTokenSource(); - Task downloadTask = downloadHandler.DownloadToFolderAsync(targetDir, tokenSource.Token); - + Task downloadTask = Task.Run(async () => + { + await downloadHandler.SetupAsync(targetDir, file => true, tokenSource.Token); + await downloadHandler.VerifyAsync(tokenSource.Token); + await downloadHandler.DownloadAsync(tokenSource.Token); + }); Parameters.Output += "\nOK."; @@ -692,7 +692,12 @@ private async Task DownloadForMultiple(IDownloadHandler downloadHandler, string }; downloadHandler.DownloadComplete += (_, _) => Parameters.Output += "\n Download completed"; - Task downloadTask = downloadHandler.DownloadToFolderAsync(targetDir, tokenSource.Token); + Task downloadTask = Task.Run(async () => + { + await downloadHandler.SetupAsync(targetDir, file => true, tokenSource.Token); + await downloadHandler.VerifyAsync(tokenSource.Token); + await downloadHandler.DownloadAsync(tokenSource.Token); + }); Parameters.Output += "\n OK."; @@ -746,6 +751,11 @@ private void RaisePropertyChanged(string property) if (PropertyChanged == null) return; PropertyChanged(this, new PropertyChangedEventArgs(property)); } + + public void Dispose() + { + tokenSource.Dispose(); + } } public static class UpdateState diff --git a/FASTER/Views/About.xaml b/FASTER/Views/About.xaml index 382fee08..9c0d662f 100644 --- a/FASTER/Views/About.xaml +++ b/FASTER/Views/About.xaml @@ -79,7 +79,7 @@ diff --git a/FASTERTests/FASTERTests.csproj b/FASTERTests/FASTERTests.csproj index 77d28e29..e56945dc 100644 --- a/FASTERTests/FASTERTests.csproj +++ b/FASTERTests/FASTERTests.csproj @@ -1,6 +1,6 @@  - net7.0-windows + net8.0-windows false @@ -19,13 +19,13 @@ x64 - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + all diff --git a/FASTERTests/Models/Arma3ProfileTests.cs b/FASTERTests/Models/Arma3ProfileTests.cs index d922e1ad..6e43a9cd 100644 --- a/FASTERTests/Models/Arma3ProfileTests.cs +++ b/FASTERTests/Models/Arma3ProfileTests.cs @@ -14,33 +14,33 @@ public void Arma3ProfileSetUp() [Test()] public void Arma3ProfileCorrectData() { - Assert.IsTrue(ProfileCfgArrays.AiPresetStrings.Contains(_p.AiLevelPreset)); - Assert.IsTrue(ProfileCfgArrays.ThirdPersonStrings.Contains(_p.ThirdPersonView)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.ReducedDamage)); - Assert.IsTrue(ProfileCfgArrays.LimitedDistanceStrings.Contains(_p.GroupIndicators)); - Assert.IsTrue(ProfileCfgArrays.LimitedDistanceStrings.Contains(_p.FriendlyTags)); - Assert.IsTrue(ProfileCfgArrays.LimitedDistanceStrings.Contains(_p.EnemyTags)); - Assert.IsTrue(ProfileCfgArrays.LimitedDistanceStrings.Contains(_p.DetectedMines)); - Assert.IsTrue(ProfileCfgArrays.FadeOutStrings.Contains(_p.Commands)); - Assert.IsTrue(ProfileCfgArrays.FadeOutStrings.Contains(_p.Waypoints)); - Assert.IsTrue(ProfileCfgArrays.FadeOutStrings.Contains(_p.WeaponInfo)); - Assert.IsTrue(ProfileCfgArrays.FadeOutStrings.Contains(_p.StanceIndicator)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.StaminaBar)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.WeaponCrosshair)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.VisionAid)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.CameraShake)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.ScoreTable)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.DeathMessages)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.VonID)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.MapContentEnemy)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.MapContentFriendly)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.MapContentMines)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.AutoReport)); - Assert.IsTrue(ProfileCfgArrays.EnabledStrings.Contains(_p.MultipleSaves)); - Assert.IsTrue(ProfileCfgArrays.TacticalPingStrings.Contains(_p.TacticalPing)); - Assert.IsFalse(string.IsNullOrWhiteSpace(_p.ArmaProfileContent)); - Assert.IsNotNull(_p.PrecisionAi); - Assert.IsNotNull(_p.SkillAi); + Assert.That(ProfileCfgArrays.AiPresetStrings.Contains(_p.AiLevelPreset)); + Assert.That(ProfileCfgArrays.ThirdPersonStrings.Contains(_p.ThirdPersonView)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.ReducedDamage)); + Assert.That(ProfileCfgArrays.LimitedDistanceStrings.Contains(_p.GroupIndicators)); + Assert.That(ProfileCfgArrays.LimitedDistanceStrings.Contains(_p.FriendlyTags)); + Assert.That(ProfileCfgArrays.LimitedDistanceStrings.Contains(_p.EnemyTags)); + Assert.That(ProfileCfgArrays.LimitedDistanceStrings.Contains(_p.DetectedMines)); + Assert.That(ProfileCfgArrays.FadeOutStrings.Contains(_p.Commands)); + Assert.That(ProfileCfgArrays.FadeOutStrings.Contains(_p.Waypoints)); + Assert.That(ProfileCfgArrays.FadeOutStrings.Contains(_p.WeaponInfo)); + Assert.That(ProfileCfgArrays.FadeOutStrings.Contains(_p.StanceIndicator)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.StaminaBar)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.WeaponCrosshair)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.VisionAid)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.CameraShake)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.ScoreTable)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.DeathMessages)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.VonID)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.MapContentEnemy)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.MapContentFriendly)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.MapContentMines)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.AutoReport)); + Assert.That(ProfileCfgArrays.EnabledStrings.Contains(_p.MultipleSaves)); + Assert.That(ProfileCfgArrays.TacticalPingStrings.Contains(_p.TacticalPing)); + Assert.That(!string.IsNullOrWhiteSpace(_p.ArmaProfileContent)); + Assert.That(_p.PrecisionAi, Is.Not.Null); + Assert.That(_p.SkillAi, Is.Not.Null); } [Test()] diff --git a/FASTERTests/Models/ArmaModCollectionTests.cs b/FASTERTests/Models/ArmaModCollectionTests.cs index c10b345a..b29121e7 100644 --- a/FASTERTests/Models/ArmaModCollectionTests.cs +++ b/FASTERTests/Models/ArmaModCollectionTests.cs @@ -36,17 +36,17 @@ public void AddSteamModTest() [Test] public void TestSteamModGet() { - Assert.IsFalse(string.IsNullOrEmpty(_mod.Author)); - Assert.IsFalse(string.IsNullOrEmpty(_mod.Name)); - Assert.IsFalse(string.IsNullOrEmpty(_mod.Path)); - Assert.IsFalse(string.IsNullOrEmpty(_mod.Status)); - Assert.IsNotNull(_mod.Size); - Assert.IsNotNull(_mod.LocalLastUpdated); - Assert.IsNotNull(_mod.WorkshopId); - Assert.IsNotNull(_mod.SteamLastUpdated); - Assert.IsNotNull(_mod.PrivateMod); - Assert.IsNotNull(_mod.IsLocal); - Assert.IsNotNull(_mod.IsLoading); + Assert.That(!string.IsNullOrEmpty(_mod.Author)); + Assert.That(!string.IsNullOrEmpty(_mod.Name)); + Assert.That(!string.IsNullOrEmpty(_mod.Path)); + Assert.That(!string.IsNullOrEmpty(_mod.Status)); + Assert.That(_mod.Size, Is.Not.Null); + Assert.That(_mod.LocalLastUpdated, Is.Not.Null); + Assert.That(_mod.WorkshopId, Is.Not.Null); + Assert.That(_mod.SteamLastUpdated, Is.Not.Null); + Assert.That(_mod.PrivateMod, Is.Not.Null); + Assert.That(_mod.IsLocal, Is.Not.Null); + Assert.That(_mod.IsLoading, Is.Not.Null); } [Test] diff --git a/FASTERTests/Models/BasicCfgTests.cs b/FASTERTests/Models/BasicCfgTests.cs index 784f89a3..f11b3643 100644 --- a/FASTERTests/Models/BasicCfgTests.cs +++ b/FASTERTests/Models/BasicCfgTests.cs @@ -16,20 +16,20 @@ public void BasicCfgSetUp() [Test()] public void BasicCfgGetTest() { - Assert.IsNotNull(_cfg.BasicContent); - Assert.IsNotNull(_cfg.MaxBandwidth); - Assert.IsNotNull(_cfg.MaxCustomFileSize); - Assert.IsNotNull(_cfg.MaxMsgSend); - Assert.IsNotNull(_cfg.MaxPacketSize); - Assert.IsNotNull(_cfg.MaxSizeGuaranteed); - Assert.IsNotNull(_cfg.MaxSizeNonGuaranteed); - Assert.IsNotNull(_cfg.MinBandwidth); - Assert.IsNotNull(_cfg.MinErrorToSend); - Assert.IsNotNull(_cfg.MinErrorToSend); - Assert.IsNotNull(_cfg.MinErrorToSendNear); - Assert.AreEqual("Custom", _cfg.PerfPreset); - Assert.IsNotNull(_cfg.TerrainGrid); - Assert.IsNotNull(_cfg.ViewDistance); + Assert.That(_cfg.BasicContent, Is.Not.Null); + Assert.That(_cfg.MaxBandwidth, Is.Not.Null); + Assert.That(_cfg.MaxCustomFileSize, Is.Not.Null); + Assert.That(_cfg.MaxMsgSend, Is.Not.Null); + Assert.That(_cfg.MaxPacketSize, Is.Not.Null); + Assert.That(_cfg.MaxSizeGuaranteed, Is.Not.Null); + Assert.That(_cfg.MaxSizeNonGuaranteed, Is.Not.Null); + Assert.That(_cfg.MinBandwidth, Is.Not.Null); + Assert.That(_cfg.MinErrorToSend, Is.Not.Null); + Assert.That(_cfg.MinErrorToSend, Is.Not.Null); + Assert.That(_cfg.MinErrorToSendNear, Is.Not.Null); + Assert.That(_cfg.PerfPreset, Is.EqualTo("Custom")); + Assert.That(_cfg.TerrainGrid, Is.Not.Null); + Assert.That(_cfg.ViewDistance, Is.Not.Null); } [Test()] diff --git a/FASTERTests/Models/ConverterTests.cs b/FASTERTests/Models/ConverterTests.cs index c867f8a6..1a2ce1b9 100644 --- a/FASTERTests/Models/ConverterTests.cs +++ b/FASTERTests/Models/ConverterTests.cs @@ -13,8 +13,8 @@ public class ProfileModsFilterIsInvalidTextConverterTests [Test()] public void ConvertTest() { - Assert.AreEqual(" ", _converter.Convert(false, typeof(string), null, System.Globalization.CultureInfo.InvariantCulture)); - Assert.AreEqual("Invalid regular expression...", _converter.Convert(true, typeof(string), null, System.Globalization.CultureInfo.InvariantCulture)); + Assert.That(_converter.Convert(false, typeof(string), null, System.Globalization.CultureInfo.InvariantCulture), Is.EqualTo(" ")); + Assert.That(_converter.Convert(true, typeof(string), null, System.Globalization.CultureInfo.InvariantCulture), Is.EqualTo("Invalid regular expression...")); } [Test()] @@ -35,8 +35,8 @@ public void ConvertTest() SolidColorBrush c1 = _converter.Convert(true, typeof(SolidColorBrush), null, System.Globalization.CultureInfo.InvariantCulture) as SolidColorBrush; SolidColorBrush c2 = _converter.Convert(false, typeof(SolidColorBrush), null, System.Globalization.CultureInfo.InvariantCulture) as SolidColorBrush; - Assert.AreEqual(new SolidColorBrush(Color.FromRgb(90, 29, 29)).Color, c1.Color); - Assert.AreEqual(new SolidColorBrush().Color, c2.Color); + Assert.That(c1.Color, Is.EqualTo(new SolidColorBrush(Color.FromRgb(90, 29, 29)).Color)); + Assert.That(c2.Color, Is.EqualTo(new SolidColorBrush().Color)); } [Test()] @@ -56,8 +56,8 @@ public void ConvertTest() SolidColorBrush c1 = _converter.Convert(true, typeof(SolidColorBrush), null, System.Globalization.CultureInfo.InvariantCulture) as SolidColorBrush; SolidColorBrush c2 = _converter.Convert(false, typeof(SolidColorBrush), null, System.Globalization.CultureInfo.InvariantCulture) as SolidColorBrush; - Assert.AreEqual(new SolidColorBrush(Color.FromRgb(190, 17, 0)).Color, c1.Color); - Assert.AreEqual(new SolidColorBrush().Color, c2.Color); + Assert.That(c1.Color, Is.EqualTo(new SolidColorBrush(Color.FromRgb(190, 17, 0)).Color)); + Assert.That(c2.Color, Is.EqualTo(new SolidColorBrush().Color)); } [Test()] @@ -74,8 +74,8 @@ public class NotBooleanToVisibilityConverterTests [Test()] public void ConvertTest() { - Assert.AreEqual(System.Windows.Visibility.Visible, _converter.Convert(false, typeof(System.Windows.Visibility), null, System.Globalization.CultureInfo.InvariantCulture)); - Assert.AreEqual(System.Windows.Visibility.Collapsed, _converter.Convert(true, typeof(System.Windows.Visibility), null, System.Globalization.CultureInfo.InvariantCulture)); + Assert.That(_converter.Convert(false, typeof(System.Windows.Visibility), null, System.Globalization.CultureInfo.InvariantCulture), Is.EqualTo(System.Windows.Visibility.Visible)); + Assert.That(_converter.Convert(true, typeof(System.Windows.Visibility), null, System.Globalization.CultureInfo.InvariantCulture), Is.EqualTo(System.Windows.Visibility.Collapsed)); } [Test()] @@ -93,15 +93,15 @@ public class FolderSizeConverterTests public void ConvertTest() { var separator = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator; - Assert.AreEqual($" 1{separator}00 B", _converter.Convert((long)1, typeof(string), null, System.Globalization.CultureInfo.InvariantCulture)); - Assert.AreEqual($" 1{separator}00 KB", _converter.Convert((long)1024, typeof(string), null, System.Globalization.CultureInfo.InvariantCulture)); - Assert.AreEqual("0 B", _converter.Convert("FAIL", typeof(string), null, System.Globalization.CultureInfo.InvariantCulture)); + Assert.That(_converter.Convert((long)1, typeof(string), null, System.Globalization.CultureInfo.InvariantCulture), Is.EqualTo($" 1{separator}00 B")); + Assert.That(_converter.Convert((long)1024, typeof(string), null, System.Globalization.CultureInfo.InvariantCulture), Is.EqualTo($" 1{separator}00 KB")); + Assert.That(_converter.Convert("FAIL", typeof(string), null, System.Globalization.CultureInfo.InvariantCulture), Is.EqualTo("0 B")); } [Test()] public void ConvertBackTest() { - Assert.IsNull(_converter.ConvertBack(1, typeof(string), null, null)); + Assert.That(_converter.ConvertBack(1, typeof(string), null, null), Is.Null); } } } \ No newline at end of file diff --git a/FASTERTests/Models/EncryptionTests.cs b/FASTERTests/Models/EncryptionTests.cs index 625b4601..13e1bc79 100644 --- a/FASTERTests/Models/EncryptionTests.cs +++ b/FASTERTests/Models/EncryptionTests.cs @@ -1,22 +1,26 @@ using NUnit.Framework; +using System.Runtime.Versioning; + namespace FASTER.Models.Tests { [TestFixture()] public class EncryptionTests { + [SupportedOSPlatform("windows7.0")] [Test()] public void EncryptDataTest() { Assert.DoesNotThrow(() => Encryption.Instance.EncryptData("SomeText")); - Assert.AreNotEqual("SomeText", Encryption.Instance.EncryptData("SomeText")); + Assert.That(Encryption.Instance.EncryptData("SomeText"), Is.Not.EqualTo("SomeText")); } + [SupportedOSPlatform("windows7.0")] [Test()] public void DecryptDataTest() { var encrypted = Encryption.Instance.EncryptData("SomeText"); - Assert.AreEqual("SomeText", Encryption.Instance.DecryptData(encrypted)); + Assert.That(Encryption.Instance.DecryptData(encrypted), Is.EqualTo("SomeText")); } } } \ No newline at end of file diff --git a/FASTERTests/SteamModTests.cs b/FASTERTests/SteamModTests.cs index 878d700b..39771a75 100644 --- a/FASTERTests/SteamModTests.cs +++ b/FASTERTests/SteamModTests.cs @@ -12,11 +12,11 @@ public class SteamModTests [Test()] public void SteamIdFromUrlTest() { - Assert.AreEqual(463939057, SteamMod.SteamIdFromUrl("https://steamcommunity.com/workshop/filedetails/?id=463939057")); - Assert.AreEqual(463939057, SteamMod.SteamIdFromUrl("https://steamcommunity.com/workshop/filedetails/?id=463939057&l=french")); - Assert.AreEqual(463939057, SteamMod.SteamIdFromUrl("https://steamcommunity.com/sharedfiles/filedetails/?l=german&id=463939057")); - Assert.AreEqual(463939057, SteamMod.SteamIdFromUrl("https://steamcommunity.com/workshop/filedetails/?l=french&id=463939057")); - Assert.AreEqual(463939057, SteamMod.SteamIdFromUrl("https://steamcommunity.com/workshop/filedetails/?l=english&id=463939057&l=french")); + Assert.That(SteamMod.SteamIdFromUrl("https://steamcommunity.com/workshop/filedetails/?id=463939057"), Is.EqualTo(463939057)); + Assert.That(SteamMod.SteamIdFromUrl("https://steamcommunity.com/workshop/filedetails/?id=463939057&l=french"), Is.EqualTo(463939057)); + Assert.That(SteamMod.SteamIdFromUrl("https://steamcommunity.com/sharedfiles/filedetails/?l=german&id=463939057"), Is.EqualTo(463939057)); + Assert.That(SteamMod.SteamIdFromUrl("https://steamcommunity.com/workshop/filedetails/?l=french&id=463939057"), Is.EqualTo(463939057)); + Assert.That(SteamMod.SteamIdFromUrl("https://steamcommunity.com/workshop/filedetails/?l=english&id=463939057&l=french"), Is.EqualTo(463939057)); } @@ -26,9 +26,9 @@ public void GetModInfoTest() Tuple expected = new Tuple("ace", "acemod", 1577907553); Tuple res = null; Assert.DoesNotThrow(() => { res = SteamMod.GetModInfo(463939057); }); - Assert.AreEqual(expected.Item1, res.Item1, "The expected mod name was wrong"); - Assert.AreEqual(expected.Item2, res.Item2, "The expected creator name was wrong"); - Assert.GreaterOrEqual(res.Item3, expected.Item3, "The expected update time was wrong"); + Assert.That(res.Item1, Is.EqualTo(expected.Item1), "The expected mod name was wrong"); + Assert.That(res.Item2, Is.EqualTo(expected.Item2), "The expected creator name was wrong"); + Assert.That(res.Item3, Is.GreaterThanOrEqualTo(expected.Item3), "The expected update time was wrong"); } } @@ -48,10 +48,10 @@ public void ParseArmaProfileFile() File.WriteAllText(fullPath, _armaProfileContent); var modList = ModUtilities.ParseModsFromArmaProfileFile(fullPath); - Assert.IsNotNull(modList); - Assert.AreEqual(1, modList.Count); - Assert.AreEqual("CBA_A3", modList[0].Name); - Assert.AreEqual(ModUtilities.GetCompareString("@CBA_A3"), ModUtilities.GetCompareString(modList[0].Name)); + Assert.That(modList, Is.Not.Null); + Assert.That(modList.Count, Is.EqualTo(1)); + Assert.That(modList[0].Name, Is.EqualTo("CBA_A3")); + Assert.That(ModUtilities.GetCompareString(modList[0].Name), Is.EqualTo(ModUtilities.GetCompareString("@CBA_A3"))); if (File.Exists(fullPath)) File.Delete(fullPath); @@ -65,15 +65,15 @@ public void ParseBuggedArmaProfileFile() File.WriteAllText(fullPath, _armaBugProfileContent); var modList = ModUtilities.ParseModsFromArmaProfileFile(fullPath); - Assert.IsNotNull(modList); - Assert.AreEqual(68, modList.Count); - Assert.AreEqual(65, modList.FindAll(mod => !mod.IsLocal).Count); - Assert.AreEqual(3, modList.FindAll(mod => mod.IsLocal).Count); + Assert.That(modList, Is.Not.Null); + Assert.That(modList.Count, Is.EqualTo(68)); + Assert.That(modList.FindAll(mod => !mod.IsLocal).Count, Is.EqualTo(65)); + Assert.That(modList.FindAll(mod => mod.IsLocal).Count, Is.EqualTo(3)); var mod = modList.Find(m => m.Name == "A3 Thermal Improvement"); - Assert.IsNotNull(mod); - Assert.IsTrue(mod.IsLocal); - Assert.AreEqual(ModUtilities.GetCompareString("@A3_Thermal_Improvement"), ModUtilities.GetCompareString(mod.Name)); + Assert.That(mod, Is.Not.Null); + Assert.That(mod.IsLocal); + Assert.That(ModUtilities.GetCompareString(mod.Name), Is.EqualTo(ModUtilities.GetCompareString("@A3_Thermal_Improvement"))); if (File.Exists(fullPath)) File.Delete(fullPath); diff --git a/FASTERTests/SteamWebApiTests.cs b/FASTERTests/SteamWebApiTests.cs index e51b29fe..1b5ba161 100644 --- a/FASTERTests/SteamWebApiTests.cs +++ b/FASTERTests/SteamWebApiTests.cs @@ -11,11 +11,11 @@ public class SteamWebApiTests public void GetSingleFileDetailsTest() { var res = SteamWebApi.GetSingleFileDetails(463939057); - Assert.IsNotNull(res); - Assert.AreEqual("463939057", res["publishedfileid"].ToString()); - Assert.AreEqual("76561198194647182", res["creator"].ToString()); - Assert.AreEqual("ace", res["title"].ToString()); - Assert.AreEqual("107410", res["creator_appid"].ToString()); + Assert.That(res, Is.Not.Null); + Assert.That(res["publishedfileid"].ToString(), Is.EqualTo("463939057")); + Assert.That(res["creator"].ToString(), Is.EqualTo("76561198194647182")); + Assert.That(res["title"].ToString(), Is.EqualTo("ace")); + Assert.That(res["creator_appid"].ToString(), Is.EqualTo("107410")); } } } \ No newline at end of file diff --git a/FASTER_Version.xml b/FASTER_Version.xml index 3569db0f..b1f15c50 100644 --- a/FASTER_Version.xml +++ b/FASTER_Version.xml @@ -1,6 +1,6 @@  - 1.9.5.2 + 1.9.6.1 https://github.com/Foxlider/FASTER/releases/latest/download/Release_x64.zip https://github.com/Foxlider/FASTER/releases true