Skip to content

Commit 67520cc

Browse files
committed
ensure urls end with / again
1 parent 3589047 commit 67520cc

18 files changed

+138
-130
lines changed

src/Elastic.Documentation.Navigation/Assembler/AssembledNavigation.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ void IAssignableChildrenNavigation.SetNavigationItems(IReadOnlyCollection<INavig
186186
{
187187
context.EmitError(context.ConfigurationPath, $"path_prefix is required for TOC reference: {tocRef.Source}");
188188
pathPrefix += $"bad-mapping-{tocRef.Source.Scheme}-{tocRef.Source.Host}-{tocRef.Source.AbsolutePath}".TrimEnd('/').TrimEnd('-');
189+
pathPrefix += "/";
189190
}
190191
else
191192
{

src/Elastic.Documentation.Navigation/Isolated/DocumentationSetNavigation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public string Url
114114
get
115115
{
116116
var rootUrl = HomeProvider.PathPrefix.TrimEnd('/');
117-
return string.IsNullOrEmpty(rootUrl) ? "/" : rootUrl;
117+
return string.IsNullOrEmpty(rootUrl) ? "/" : $"{rootUrl}/";
118118
}
119119
}
120120

src/Elastic.Documentation.Navigation/Isolated/FileNavigationLeaf.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,12 @@ string DetermineUrl()
5858
if (path.EndsWith("/index", StringComparison.OrdinalIgnoreCase))
5959
path = path[..^6]; // Remove "/index"
6060
else if (path.Equals("index", StringComparison.OrdinalIgnoreCase))
61-
return string.IsNullOrEmpty(rootUrl) ? "/" : rootUrl;
61+
return string.IsNullOrEmpty(rootUrl) ? "/" : $"{rootUrl}/";
6262

6363
if (string.IsNullOrEmpty(path))
64-
return string.IsNullOrEmpty(rootUrl) ? "/" : rootUrl;
64+
return string.IsNullOrEmpty(rootUrl) ? "/" : $"{rootUrl}/";
6565

66-
return $"{rootUrl}/{path}";
66+
return $"{rootUrl}/{path.TrimEnd('/')}/";
6767
}
6868
}
6969
}

src/Elastic.Documentation.Navigation/Isolated/TableOfContentsNavigation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ INavigationHomeProvider homeProvider
4646
HomeProvider = homeProvider;
4747

4848
// Create an identifier for this TOC
49-
Identifier = new Uri($"{git.RepositoryName}://{parentPath}");
49+
Identifier = new Uri($"{git.RepositoryName}://{parentPath.TrimEnd('/')}");
5050
_ = tocNodes.TryAdd(Identifier, this);
5151

5252
// FindIndex must be called after _homeProvider is set

src/Elastic.Documentation/Diagnostics/DiagnosticsCollector.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class DiagnosticsCollector(IReadOnlyCollection<IDiagnosticsOutput> output
3131

3232
public bool NoHints { get; set; }
3333

34-
public DiagnosticsCollector StartAsync(Cancel ctx)
34+
public virtual DiagnosticsCollector StartAsync(Cancel ctx)
3535
{
3636
_ = ((IHostedService)this).StartAsync(ctx);
3737
return this;
@@ -75,7 +75,7 @@ void Drain()
7575
}
7676
}
7777

78-
private void IncrementSeverityCount(Diagnostic item)
78+
protected void IncrementSeverityCount(Diagnostic item)
7979
{
8080
if (item.Severity == Severity.Error)
8181
_ = Interlocked.Increment(ref _errors);

tests/Elastic.Markdown.Tests/Inline/InlineLinkTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,10 @@ public void GeneratesHtml() =>
320320
"""
321321
<p>Links:</p>
322322
<ul>
323-
<li><a href="/docs/testing/req">Special Requirements</a></li>
323+
<li><a href="/docs/testing/req/">Special Requirements</a></li>
324324
</ul>
325325
<ul>
326-
<li><a href="/docs/testing/req">Special Requirements</a></li>
326+
<li><a href="/docs/testing/req/">Special Requirements</a></li>
327327
</ul>
328328
""");
329329

tests/Navigation.Tests/Assembler/ComplexSiteNavigationTests.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,45 +65,45 @@ public void ComplexNavigationWithMultipleNestedTocsAppliesPathPrefixToRootUrls()
6565
// Test 1: Observability - verify root URL has path prefix
6666
var observability = siteNavigation.NavigationItems.ElementAt(0) as INodeNavigationItem<INavigationModel, INavigationItem>;
6767
observability.Should().NotBeNull();
68-
observability.Url.Should().Be("/serverless/observability");
68+
observability.Url.Should().Be("/serverless/observability/");
6969
observability.NavigationTitle.Should().Be(observability.Index.NavigationTitle);
7070

7171
// Test 2: Serverless Search - verify root URL has path prefix
7272
var search = siteNavigation.NavigationItems.ElementAt(1);
7373
search.Should().NotBeNull();
74-
search.Url.Should().Be("/serverless/search");
74+
search.Url.Should().Be("/serverless/search/");
7575

7676
// Test 3: Platform - verify root URL has path prefix
7777
var platform = siteNavigation.NavigationItems.ElementAt(2) as INodeNavigationItem<INavigationModel, INavigationItem>;
7878
platform.Should().NotBeNull();
79-
platform.Url.Should().Be("/platform");
79+
platform.Url.Should().Be("/platform/");
8080
platform.NavigationItems.Should().HaveCount(2, "platform should only show the two nested TOCs as children");
8181

8282
// Verify nested TOC URLs have their specified path prefixes
8383
var deploymentGuide = platform.NavigationItems.ElementAt(0) as INodeNavigationItem<INavigationModel, INavigationItem>;
8484
deploymentGuide.Should().NotBeNull();
85-
deploymentGuide.Url.Should().Be("/platform/deployment");
85+
deploymentGuide.Url.Should().Be("/platform/deployment/");
8686
deploymentGuide.NavigationTitle.Should().Be(deploymentGuide.Index.NavigationTitle);
8787

8888
var cloudGuide = platform.NavigationItems.ElementAt(1);
8989
cloudGuide.Should().NotBeNull();
90-
cloudGuide.Url.Should().Be("/platform/cloud");
90+
cloudGuide.Url.Should().Be("/platform/cloud/");
9191
cloudGuide.NavigationTitle.Should().Be("Cloud Guide");
9292

9393
// Test 4: Elasticsearch Reference - verify root URL has path prefix
9494
var elasticsearch = siteNavigation.NavigationItems.ElementAt(3) as INodeNavigationItem<INavigationModel, INavigationItem>;
9595
elasticsearch.Should().NotBeNull();
96-
elasticsearch.Url.Should().Be("/elasticsearch/reference");
96+
elasticsearch.Url.Should().Be("/elasticsearch/reference/");
9797
elasticsearch.NavigationItems.Should().HaveCount(2, "elasticsearch should have read its toc");
9898

9999
// rest-apis is a folder (not a TOC)
100100
var restApis = elasticsearch.NavigationItems.ElementAt(0).Should().BeOfType<FolderNavigation>().Subject;
101-
restApis.Url.Should().Be("/elasticsearch/reference/rest-apis");
101+
restApis.Url.Should().Be("/elasticsearch/reference/rest-apis/");
102102
restApis.NavigationItems.Should().HaveCount(2, "rest-apis folder should have 2 files");
103103

104104
// Verify the file inside the folder has the correct path prefix
105105
var documentApisFile = restApis.NavigationItems.ElementAt(0).Should().BeOfType<FileNavigationLeaf<IDocumentationFile>>().Subject;
106-
documentApisFile.Url.Should().Be("/elasticsearch/reference/rest-apis/document-apis");
106+
documentApisFile.Url.Should().Be("/elasticsearch/reference/rest-apis/document-apis/");
107107
documentApisFile.NavigationTitle.Should().Be("Document APIs");
108108
}
109109

@@ -135,7 +135,7 @@ public void DeeplyNestedNavigationMaintainsPathPrefixThroughoutHierarchy()
135135

136136
var platform = siteNavigation.NavigationItems.First() as INodeNavigationItem<INavigationModel, INavigationItem>;
137137
platform.Should().NotBeNull();
138-
platform.Url.Should().Be("/docs/platform");
138+
platform.Url.Should().Be("/docs/platform/");
139139

140140
// Platform should have its children (deployment-guide, cloud-guide)
141141
platform.NavigationItems.Should().HaveCount(2);
@@ -144,12 +144,12 @@ public void DeeplyNestedNavigationMaintainsPathPrefixThroughoutHierarchy()
144144
var deploymentGuide = platform.NavigationItems.ElementAt(0) as INodeNavigationItem<INavigationModel, INavigationItem>;
145145
deploymentGuide.Should().NotBeNull();
146146
deploymentGuide.Should().BeOfType<TableOfContentsNavigation>();
147-
deploymentGuide.Url.Should().StartWith("/docs/platform");
147+
deploymentGuide.Url.Should().StartWith("/docs/platform/");
148148

149149
// Walk through the entire tree and verify every single URL starts with a path prefix
150150
var allUrls = CollectAllUrls(platform.NavigationItems);
151151
allUrls.Should().NotBeEmpty();
152-
allUrls.Should().OnlyContain(url => url.StartsWith("/docs/platform"),
152+
allUrls.Should().OnlyContain(url => url.StartsWith("/docs/platform/"),
153153
"all URLs in platform should start with /docs/platform");
154154
}
155155

tests/Navigation.Tests/Assembler/IdentifierCollectionTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,12 @@ public void TableOfContentsNavigationHasCorrectIdentifier()
7676
var platformNav = new DocumentationSetNavigation<IDocumentationFile>(platformDocset, platformContext, GenericDocumentationFileFactory.Instance);
7777

7878
// Get the deployment-guide TOC
79-
var deploymentGuide = platformNav.NavigationItems.ElementAt(1) as TableOfContentsNavigation;
79+
var deploymentGuide = platformNav.NavigationItems.ElementAt(0) as TableOfContentsNavigation;
8080
deploymentGuide.Should().NotBeNull();
8181
deploymentGuide.Identifier.Should().Be(new Uri("platform://deployment-guide"));
8282

8383
// Get the cloud-guide TOC
84-
var cloudGuide = platformNav.NavigationItems.ElementAt(2) as TableOfContentsNavigation;
84+
var cloudGuide = platformNav.NavigationItems.ElementAt(1) as TableOfContentsNavigation;
8585
cloudGuide.Should().NotBeNull();
8686
cloudGuide.Identifier.Should().Be(new Uri("platform://cloud-guide"));
8787
}

tests/Navigation.Tests/Assembler/SiteDocumentationSetsTests.cs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,14 @@ public void SiteNavigationIntegratesWithDocumentationSets()
101101
siteNavigation.NavigationItems.Should().HaveCount(3);
102102

103103
var observability = siteNavigation.NavigationItems.ElementAt(0);
104-
observability.Url.Should().Be("/serverless/observability");
104+
observability.Url.Should().Be("/serverless/observability/");
105105
observability.NavigationTitle.Should().NotBeNullOrEmpty();
106106

107107
var search = siteNavigation.NavigationItems.ElementAt(1);
108-
search.Url.Should().Be("/serverless/search");
108+
search.Url.Should().Be("/serverless/search/");
109109

110110
var security = siteNavigation.NavigationItems.ElementAt(2);
111-
security.Url.Should().Be("/serverless/security");
111+
security.Url.Should().Be("/serverless/security/");
112112
}
113113

114114
[Fact]
@@ -135,8 +135,8 @@ public void SiteNavigationWithNestedTocs()
135135
var platformNav = new DocumentationSetNavigation<IDocumentationFile>(platformDocset, platformContext, GenericDocumentationFileFactory.Instance);
136136
platformNav.Url.Should().Be("/");
137137
platformNav.Index.Url.Should().Be("/");
138-
platformNav.NavigationItems.ElementAt(0).Url.Should().Be("/deployment-guide");
139-
platformNav.NavigationItems.ElementAt(1).Url.Should().Be("/cloud-guide");
138+
platformNav.NavigationItems.ElementAt(0).Url.Should().Be("/deployment-guide/");
139+
platformNav.NavigationItems.ElementAt(1).Url.Should().Be("/cloud-guide/");
140140

141141
var documentationSets = new List<IDocumentationSetNavigation> { platformNav };
142142

@@ -148,14 +148,14 @@ public void SiteNavigationWithNestedTocs()
148148

149149
var platform = siteNavigation.NavigationItems.First() as INodeNavigationItem<INavigationModel, INavigationItem>;
150150
platform.Should().NotBeNull();
151-
platform.Url.Should().Be("/platform");
151+
platform.Url.Should().Be("/platform/");
152152
platform.NavigationItems.Should().HaveCount(2);
153153

154154
var deployment = platform.NavigationItems.ElementAt(0);
155-
deployment.Url.Should().Be("/platform/deployment");
155+
deployment.Url.Should().Be("/platform/deployment/");
156156

157157
var cloud = platform.NavigationItems.ElementAt(1);
158-
cloud.Url.Should().Be("/platform/cloud");
158+
cloud.Url.Should().Be("/platform/cloud/");
159159
}
160160

161161
[Fact]
@@ -214,21 +214,21 @@ public void SiteNavigationWithAllRepositories()
214214

215215
// Verify top-level items
216216
var observability = siteNavigation.NavigationItems.ElementAt(0);
217-
observability.Url.Should().Be("/serverless/observability");
217+
observability.Url.Should().Be("/serverless/observability/");
218218

219219
var search = siteNavigation.NavigationItems.ElementAt(1);
220-
search.Url.Should().Be("/serverless/search");
220+
search.Url.Should().Be("/serverless/search/");
221221

222222
var security = siteNavigation.NavigationItems.ElementAt(2);
223-
security.Url.Should().Be("/serverless/security");
223+
security.Url.Should().Be("/serverless/security/");
224224

225225
var platform = siteNavigation.NavigationItems.ElementAt(3) as INodeNavigationItem<INavigationModel, INavigationItem>;
226226
platform.Should().NotBeNull();
227-
platform.Url.Should().Be("/platform");
228-
platform.NavigationItems.Should().HaveCount(3);
227+
platform.Url.Should().Be("/platform/");
228+
platform.NavigationItems.Should().HaveCount(2);
229229

230230
var elasticsearch = siteNavigation.NavigationItems.ElementAt(4);
231-
elasticsearch.Url.Should().Be("/elasticsearch/reference");
231+
elasticsearch.Url.Should().Be("/elasticsearch/reference/");
232232
}
233233

234234
[Fact]
@@ -279,13 +279,13 @@ public void DocumentationSetWithNestedTocs()
279279

280280
var deploymentGuide = platformNav.NavigationItems.ElementAt(0);
281281
deploymentGuide.Should().BeOfType<TableOfContentsNavigation>();
282-
deploymentGuide.Url.Should().Be("/deployment-guide");
282+
deploymentGuide.Url.Should().Be("/deployment-guide/");
283283
var deploymentToc = (TableOfContentsNavigation)deploymentGuide;
284284
deploymentToc.NavigationItems.Should().HaveCount(1); // self-managed folder
285285

286286
var cloudGuide = platformNav.NavigationItems.ElementAt(1);
287287
cloudGuide.Should().BeOfType<TableOfContentsNavigation>();
288-
cloudGuide.Url.Should().Be("/cloud-guide");
288+
cloudGuide.Url.Should().Be("/cloud-guide/");
289289
var cloudToc = (TableOfContentsNavigation)cloudGuide;
290290
cloudToc.NavigationItems.Should().HaveCount(2); // aws folder, azure folder
291291
}
@@ -373,14 +373,14 @@ public void SiteNavigationWithNestedTocsAppliesCorrectPathPrefixes()
373373

374374
var platform = siteNavigation.NavigationItems.First() as INodeNavigationItem<INavigationModel, INavigationItem>;
375375
platform.Should().NotBeNull();
376-
platform.Url.Should().Be("/platform");
376+
platform.Url.Should().Be("/platform/");
377377

378378
// Verify child TOCs have their specific path prefixes
379379
var deployment = platform.NavigationItems.ElementAt(0);
380-
deployment.Url.Should().StartWith("/platform/deployment");
380+
deployment.Url.Should().StartWith("/platform/deployment/");
381381

382382
var cloud = platform.NavigationItems.ElementAt(1);
383-
cloud.Url.Should().StartWith("/platform/cloud");
383+
cloud.Url.Should().StartWith("/platform/cloud/");
384384
}
385385

386386
[Fact]
@@ -409,7 +409,7 @@ public void SiteNavigationRequiresPathPrefix()
409409
toc.Should().NotBeNull();
410410
toc.HomeProvider.PathPrefix.Should().Be("/bad-mapping-observability");
411411
// toc has no `path_prefix` so it will use a default ugly one to avoid clashes and emit an error
412-
toc.Url.Should().Be("/bad-mapping-observability");
412+
toc.Url.Should().Be("/bad-mapping-observability/");
413413
}
414414

415415
[Fact]
@@ -583,12 +583,12 @@ public void DocumentationSetNavigationWithFoldersHasNoDiagnostics()
583583

584584
// Assert navigation was created successfully with folders
585585
navigation.Should().NotBeNull();
586-
navigation.NavigationItems.Should().HaveCount(3); // index.md, getting-started folder, monitoring folder
586+
navigation.NavigationItems.Should().HaveCount(2); // index.md, getting-started folder, monitoring folder
587587

588-
var gettingStarted = navigation.NavigationItems.ElementAt(1);
588+
var gettingStarted = navigation.NavigationItems.ElementAt(0);
589589
gettingStarted.Should().BeOfType<FolderNavigation>();
590590

591-
var monitoring = navigation.NavigationItems.ElementAt(2);
591+
var monitoring = navigation.NavigationItems.ElementAt(1);
592592
monitoring.Should().BeOfType<FolderNavigation>();
593593

594594
// Assert no diagnostic errors or warnings

tests/Navigation.Tests/Assembler/SiteNavigationTests.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,16 +129,16 @@ public void SitePrefixNormalizesSlashes(string? sitePrefix, string expectedRootU
129129
}
130130

131131
[Theory]
132-
[InlineData(null, "/observability")]
133-
[InlineData("", "/observability")]
134-
[InlineData("docs", "/docs/observability")]
135-
[InlineData("/docs", "/docs/observability")]
136-
[InlineData("docs/", "/docs/observability")]
137-
[InlineData("/docs/", "/docs/observability")]
138-
[InlineData("api/docs", "/api/docs/observability")]
139-
[InlineData("/api/docs", "/api/docs/observability")]
140-
[InlineData("api/docs/", "/api/docs/observability")]
141-
[InlineData("/api/docs/", "/api/docs/observability")]
132+
[InlineData(null, "/observability/")]
133+
[InlineData("", "/observability/")]
134+
[InlineData("docs", "/docs/observability/")]
135+
[InlineData("/docs", "/docs/observability/")]
136+
[InlineData("docs/", "/docs/observability/")]
137+
[InlineData("/docs/", "/docs/observability/")]
138+
[InlineData("api/docs", "/api/docs/observability/")]
139+
[InlineData("/api/docs", "/api/docs/observability/")]
140+
[InlineData("api/docs/", "/api/docs/observability/")]
141+
[InlineData("/api/docs/", "/api/docs/observability/")]
142142
public void SitePrefixAppliedToNavigationItemUrls(string? sitePrefix, string expectedObservabilityUrl)
143143
{
144144
// language=yaml
@@ -166,11 +166,11 @@ public void SitePrefixAppliedToNavigationItemUrls(string? sitePrefix, string exp
166166
}
167167

168168
[Theory]
169-
[InlineData(null, "/observability", "/search")]
170-
[InlineData("docs", "/docs/observability", "/docs/search")]
171-
[InlineData("/docs", "/docs/observability", "/docs/search")]
172-
[InlineData("docs/", "/docs/observability", "/docs/search")]
173-
[InlineData("/docs/", "/docs/observability", "/docs/search")]
169+
[InlineData(null, "/observability/", "/search/")]
170+
[InlineData("docs", "/docs/observability/", "/docs/search/")]
171+
[InlineData("/docs", "/docs/observability/", "/docs/search/")]
172+
[InlineData("docs/", "/docs/observability/", "/docs/search/")]
173+
[InlineData("/docs/", "/docs/observability/", "/docs/search/")]
174174
public void SitePrefixAppliedToMultipleNavigationItems(string? sitePrefix, string expectedObsUrl, string expectedSearchUrl)
175175
{
176176
// language=yaml

0 commit comments

Comments
 (0)