- 43 tests across SlugGuard, ReplContext navigation, NotesCache.TimeAgo - SlugGuard moved to NozCli.Core.Security (shared between REPL and tests) - Bug fix: FoldersInView() now returns only actual sub-folders, not note segments (previously cd tab-completion suggested note names as navigable folders) - .forgejo/workflows/ci.yml: build + test on every push/PR
165 lines
5.7 KiB
C#
165 lines
5.7 KiB
C#
using Xunit;
|
|
using NozCli.Core.Config;
|
|
using NozCli.Core.Models;
|
|
using NozCli.Repl;
|
|
|
|
namespace NozCli.Tests;
|
|
|
|
public class ReplContextTests
|
|
{
|
|
// Builds a ReplContext with a fixed NoteCache — no API calls made.
|
|
private static ReplContext BuildCtx(params NoteInfo[] notes)
|
|
{
|
|
var cfg = new LocalConfig { ServerUrl = "http://localhost:9999", Token = "test" };
|
|
var ctx = new ReplContext(null!, cfg); // Api is null — not used in navigation
|
|
ctx.NoteCache = [.. notes];
|
|
return ctx;
|
|
}
|
|
|
|
private static NoteInfo Note(string slug, string topic, string status = "seed") =>
|
|
new(slug, $"Title {slug}", status, topic, "de", false, null);
|
|
|
|
// ── CurrentPath ──────────────────────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void CurrentPath_AtRoot_IsWave()
|
|
{
|
|
var ctx = BuildCtx();
|
|
Assert.Equal("~", ctx.CurrentPath);
|
|
}
|
|
|
|
[Fact]
|
|
public void CurrentPath_InTopic_ShowsTopic()
|
|
{
|
|
var ctx = BuildCtx(Note("psychologie/test", "psychologie"));
|
|
ctx.NavigateTo("psychologie");
|
|
Assert.Equal("~/psychologie", ctx.CurrentPath);
|
|
}
|
|
|
|
[Fact]
|
|
public void CurrentPath_InSubfolder_ShowsFullPath()
|
|
{
|
|
var ctx = BuildCtx(Note("psychologie/sub/deep", "psychologie"));
|
|
ctx.NavigateTo("psychologie");
|
|
ctx.NavigateTo("sub");
|
|
Assert.Equal("~/psychologie/sub", ctx.CurrentPath);
|
|
}
|
|
|
|
// ── FoldersInView ────────────────────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void FoldersInView_AtRoot_ReturnsDistinctTopics()
|
|
{
|
|
var ctx = BuildCtx(
|
|
Note("psychologie/a", "psychologie"),
|
|
Note("psychologie/b", "psychologie"),
|
|
Note("biosysteme/c", "biosysteme"));
|
|
|
|
var folders = ctx.FoldersInView().OrderBy(f => f).ToList();
|
|
Assert.Equal(["biosysteme", "psychologie"], folders);
|
|
}
|
|
|
|
[Fact]
|
|
public void FoldersInView_InTopic_ReturnsSubfolders()
|
|
{
|
|
var ctx = BuildCtx(
|
|
Note("psychologie/sub/note", "psychologie"),
|
|
Note("psychologie/flat-note", "psychologie"));
|
|
|
|
ctx.NavigateTo("psychologie");
|
|
var folders = ctx.FoldersInView().ToList();
|
|
|
|
Assert.Contains("sub", folders);
|
|
Assert.DoesNotContain("flat-note", folders);
|
|
}
|
|
|
|
// ── NavigateTo / NavigateUp ──────────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void NavigateTo_ValidTopic_ReturnsTrue()
|
|
{
|
|
var ctx = BuildCtx(Note("psychologie/test", "psychologie"));
|
|
Assert.True(ctx.NavigateTo("psychologie"));
|
|
Assert.Equal("psychologie", ctx.CurrentTopic);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavigateTo_UnknownTopic_ReturnsFalse()
|
|
{
|
|
var ctx = BuildCtx(Note("psychologie/test", "psychologie"));
|
|
Assert.False(ctx.NavigateTo("doesnotexist"));
|
|
Assert.Null(ctx.CurrentTopic);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavigateUp_FromTopic_ReturnsToRoot()
|
|
{
|
|
var ctx = BuildCtx(Note("psychologie/test", "psychologie"));
|
|
ctx.NavigateTo("psychologie");
|
|
ctx.NavigateUp();
|
|
Assert.Null(ctx.CurrentTopic);
|
|
Assert.Equal("~", ctx.CurrentPath);
|
|
}
|
|
|
|
[Fact]
|
|
public void NavigateUp_FromSubfolder_ReturnsToTopic()
|
|
{
|
|
var ctx = BuildCtx(Note("psychologie/sub/deep", "psychologie"));
|
|
ctx.NavigateTo("psychologie");
|
|
ctx.NavigateTo("sub");
|
|
ctx.NavigateUp();
|
|
|
|
Assert.Equal("psychologie", ctx.CurrentTopic);
|
|
Assert.Null(ctx.CurrentSubPath);
|
|
}
|
|
|
|
// ── SlugRelative ─────────────────────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void SlugRelative_InTopic_StripsTopicPrefix()
|
|
{
|
|
var ctx = BuildCtx(Note("psychologie/flow", "psychologie"));
|
|
ctx.NavigateTo("psychologie");
|
|
Assert.Equal("flow", ctx.SlugRelative("psychologie/flow"));
|
|
}
|
|
|
|
[Fact]
|
|
public void SlugRelative_AtRoot_ReturnsFullSlug()
|
|
{
|
|
var ctx = BuildCtx(Note("psychologie/flow", "psychologie"));
|
|
Assert.Equal("psychologie/flow", ctx.SlugRelative("psychologie/flow"));
|
|
}
|
|
|
|
// ── NotesInView ──────────────────────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void NotesInView_InTopic_FiltersCorrectly()
|
|
{
|
|
var ctx = BuildCtx(
|
|
Note("psychologie/a", "psychologie"),
|
|
Note("biosysteme/b", "biosysteme"));
|
|
|
|
ctx.NavigateTo("psychologie");
|
|
var notes = ctx.NotesInView().ToList();
|
|
|
|
Assert.Single(notes);
|
|
Assert.Equal("psychologie/a", notes[0].Slug);
|
|
}
|
|
|
|
// ── ResolveSlug ──────────────────────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void ResolveSlug_ShortName_InTopic_ResolvesToFullSlug()
|
|
{
|
|
var ctx = BuildCtx(Note("psychologie/flow", "psychologie"));
|
|
ctx.NavigateTo("psychologie");
|
|
Assert.Equal("psychologie/flow", ctx.ResolveSlug("flow"));
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolveSlug_AlreadyFullSlug_ReturnsUnchanged()
|
|
{
|
|
var ctx = BuildCtx(Note("psychologie/flow", "psychologie"));
|
|
Assert.Equal("psychologie/flow", ctx.ResolveSlug("psychologie/flow"));
|
|
}
|
|
}
|