-
Notifications
You must be signed in to change notification settings - Fork 459
Expand file tree
/
Copy pathHelpUrlTests.cs
More file actions
165 lines (139 loc) · 5.23 KB
/
HelpUrlTests.cs
File metadata and controls
165 lines (139 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using NUnit.Framework;
using Unity.Netcode.Runtime;
using UnityEngine;
using UnityEngine.TestTools;
namespace Unity.Netcode.RuntimeTests
{
internal class HelpUrlTests
{
private const string k_PackageName = "com.unity.netcode.gameobjects";
private static readonly HttpClient k_HttpClient = new();
private bool m_VerboseLogging = false;
[UnityTest]
public IEnumerator ValidateUrlsAreValid()
{
var names = new List<string>();
var allUrls = new List<string>();
// GetFields() can only see public strings. Ensure each HelpUrl is public.
foreach (var constant in typeof(HelpUrls).GetFields())
{
if (constant.IsLiteral && !constant.IsInitOnly)
{
names.Add(constant.Name);
allUrls.Add((string)constant.GetValue(null));
}
}
VerboseLog($"Found {allUrls.Count} URLs");
var tasks = new List<Task<bool>>();
foreach (var url in allUrls)
{
tasks.Add(AreUnityDocsAvailableAt(url));
}
while (tasks.Any(task => !task.IsCompleted))
{
yield return new WaitForSeconds(0.01f);
}
for (int i = 0; i < allUrls.Count; i++)
{
Assert.IsTrue(tasks[i].Result, $"HelpUrls.{names[i]} has an invalid path! Path: {allUrls[i]}");
}
}
private async Task<bool> AreUnityDocsAvailableAt(string url)
{
try
{
var split = url.Split('#');
url = split[0];
var stream = await GetContentFromRemoteFile(url);
var redirectUrl = CalculateRedirectURl(url, stream);
VerboseLog($"Calculated Redirect URL: {redirectUrl}");
var content = await GetContentFromRemoteFile(redirectUrl);
// If original url had an anchor part (e.g. some/url.html#anchor)
if (split.Length > 1)
{
var anchorString = split[1];
// All headings will have an id with the anchorstring (e.g. <h2 id="anchor">)
if (!content.Contains($"id=\"{anchorString}\">"))
{
return false;
}
}
return true;
}
catch (Exception e)
{
VerboseLog(e.Message);
return false;
}
}
/// <summary>
/// Checks if a remote file at the <paramref name="url"/> exists, and if access is not restricted.
/// </summary>
/// <param name="url">URL to a remote file.</param>
/// <returns>True if the file at the <paramref name="url"/> is able to be downloaded, false if the file does not exist, or if the file is restricted.</returns>
private async Task<string> GetContentFromRemoteFile(string url)
{
//Checking if URI is well formed is optional
var uri = new Uri(url);
if (!uri.IsWellFormedOriginalString())
{
throw new Exception($"URL {url} is not well formed");
}
try
{
using var request = new HttpRequestMessage(HttpMethod.Get, uri);
using var response = await k_HttpClient.SendAsync(request);
if (!response.IsSuccessStatusCode || response.Content.Headers.ContentLength <= 0)
{
throw new Exception($"Failed to get remote file from URL {url}");
}
return await response.Content.ReadAsStringAsync();
}
catch
{
throw new Exception($"URL {url} request failed");
}
}
private string CalculateRedirectURl(string originalRequest, string content)
{
var uri = new Uri(originalRequest);
var baseRequest = $"{uri.Scheme}://{uri.Host}";
foreach (var segment in uri.Segments)
{
if (segment.Contains(k_PackageName))
{
break;
}
baseRequest += segment;
}
var subfolderRegex = new Regex(@"[?&](\w[\w.]*)=([^?&]+)").Match(uri.Query);
var subfolder = "";
foreach (Group match in subfolderRegex.Groups)
{
subfolder = match.Value;
}
string pattern = @"com.unity.netcode.gameobjects\@(\d+.\d+)";
var targetDestination = "";
foreach (Match match in Regex.Matches(content, pattern))
{
targetDestination = match.Value;
break;
}
return baseRequest + targetDestination + subfolder;
}
private void VerboseLog(string message)
{
if (m_VerboseLogging)
{
Debug.unityLogger.Log(message);
}
}
}
}