Public Access
Implement meeting assistant v1
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
using MeetingAssistant.MeetingNotes;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace MeetingAssistant.Tests;
|
||||
|
||||
public sealed class MeetingNoteStoreTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task StoreWritesTemplateFrontmatterAndReadsUserNotesBody()
|
||||
{
|
||||
var (vaultRoot, store) = CreateStore();
|
||||
var note = MeetingNoteTemplate.Create(
|
||||
title: "Leadership Sync",
|
||||
startTime: DateTimeOffset.Parse("2026-05-19T10:00:00+02:00"),
|
||||
endTime: DateTimeOffset.Parse("2026-05-19T10:30:00+02:00"),
|
||||
attendees:
|
||||
[
|
||||
"Mike <m.ike@ibm.com>",
|
||||
"Ada"
|
||||
],
|
||||
projects:
|
||||
[
|
||||
"Meeting Assistant",
|
||||
"Alaric"
|
||||
],
|
||||
transcriptPath: Path.Combine(vaultRoot, "Meetings", "Transcripts", "20260519-transcript.md"),
|
||||
assistantContextPath: Path.Combine(vaultRoot, "Meetings", "Assistant Context", "20260519-context.md"),
|
||||
summaryPath: Path.Combine(vaultRoot, "Meetings", "Summaries", "20260519-summary.md"),
|
||||
userNotes: "Discuss rollout risks.");
|
||||
|
||||
var saved = await store.SaveAsync(note, CancellationToken.None);
|
||||
var content = await File.ReadAllTextAsync(saved.Path);
|
||||
var loaded = await store.ReadAsync(saved.Path, CancellationToken.None);
|
||||
|
||||
Assert.EndsWith(".md", saved.Path, StringComparison.Ordinal);
|
||||
Assert.Contains("attendees:", content);
|
||||
Assert.Contains("- Mike <m.ike@ibm.com>", content);
|
||||
Assert.Contains("- Ada", content);
|
||||
Assert.Contains("projects:", content);
|
||||
Assert.Contains("- Meeting Assistant", content);
|
||||
Assert.DoesNotContain("purpose:", content);
|
||||
Assert.Contains("start_time: \"2026-05-19T10:00:00.0000000+02:00\"", content);
|
||||
Assert.Contains("end_time: \"2026-05-19T10:30:00.0000000+02:00\"", content);
|
||||
Assert.Contains("transcript: \"[[../Transcripts/20260519-transcript|Transcript]]\"", content);
|
||||
Assert.Contains("assistant_context: \"[[../Assistant Context/20260519-context|Assistant Context]]\"", content);
|
||||
Assert.Contains("summary: \"[[../Summaries/20260519-summary|Summary]]\"", content);
|
||||
Assert.DoesNotContain("decisions:", content);
|
||||
Assert.DoesNotContain("next_steps:", content);
|
||||
Assert.Equal("Discuss rollout risks.", loaded.UserNotes);
|
||||
Assert.Equal(["Mike <m.ike@ibm.com>", "Ada"], loaded.Frontmatter.Attendees);
|
||||
Assert.Equal(["Meeting Assistant", "Alaric"], loaded.Frontmatter.Projects);
|
||||
Assert.Equal(DateTimeOffset.Parse("2026-05-19T10:00:00+02:00"), loaded.Frontmatter.StartTime);
|
||||
Assert.Equal(DateTimeOffset.Parse("2026-05-19T10:30:00+02:00"), loaded.Frontmatter.EndTime);
|
||||
Assert.Equal("[[../Transcripts/20260519-transcript|Transcript]]", loaded.Frontmatter.Transcript);
|
||||
Assert.Equal("[[../Assistant Context/20260519-context|Assistant Context]]", loaded.Frontmatter.AssistantContext);
|
||||
Assert.Equal("[[../Summaries/20260519-summary|Summary]]", loaded.Frontmatter.Summary);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FrontmatterUpdatePreservesExistingUserNotesBody()
|
||||
{
|
||||
var (vaultRoot, store) = CreateStore();
|
||||
var userNotes = """
|
||||
## User notes
|
||||
|
||||
- First point
|
||||
- Second point
|
||||
|
||||
```text
|
||||
Keep this block exactly.
|
||||
```
|
||||
|
||||
""";
|
||||
var saved = await store.SaveAsync(
|
||||
MeetingNoteTemplate.Create(
|
||||
title: "Body Preservation",
|
||||
attendees: [],
|
||||
projects: [],
|
||||
transcriptPath: Path.Combine(vaultRoot, "Meetings", "Transcripts", "20260519-transcript.md"),
|
||||
assistantContextPath: Path.Combine(vaultRoot, "Meetings", "Assistant Context", "20260519-context.md"),
|
||||
summaryPath: Path.Combine(vaultRoot, "Meetings", "Summaries", "20260519-summary.md"),
|
||||
userNotes: userNotes),
|
||||
CancellationToken.None);
|
||||
|
||||
var loaded = await store.ReadAsync(saved.Path, CancellationToken.None);
|
||||
loaded.Frontmatter.Title = "Updated title";
|
||||
await store.SaveAsync(loaded, CancellationToken.None);
|
||||
var reloaded = await store.ReadAsync(saved.Path, CancellationToken.None);
|
||||
|
||||
Assert.Equal("Updated title", reloaded.Frontmatter.Title);
|
||||
Assert.Equal(userNotes, reloaded.UserNotes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ActionLinkEscapesSummaryFileName()
|
||||
{
|
||||
var link = MeetingNoteActionLinks.CreateSummaryRetryLink(
|
||||
"http://localhost:5090/",
|
||||
"C:\\Vault\\Meetings\\Summaries\\summary with spaces.md");
|
||||
|
||||
Assert.Equal(
|
||||
"[Retry summary generation](http://localhost:5090/meetings/summary/retry?summaryPath=summary%20with%20spaces.md)",
|
||||
link);
|
||||
}
|
||||
|
||||
private static (string VaultRoot, MarkdownMeetingNoteStore Store) CreateStore()
|
||||
{
|
||||
var vaultRoot = Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"));
|
||||
var store = new MarkdownMeetingNoteStore(
|
||||
Options.Create(new MeetingAssistantOptions
|
||||
{
|
||||
Vault = new VaultOptions
|
||||
{
|
||||
MeetingNotesFolder = Path.Combine(vaultRoot, "Meetings", "Notes"),
|
||||
TranscriptsFolder = Path.Combine(vaultRoot, "Meetings", "Transcripts"),
|
||||
AssistantContextFolder = Path.Combine(vaultRoot, "Meetings", "Assistant Context"),
|
||||
SummariesFolder = Path.Combine(vaultRoot, "Meetings", "Summaries"),
|
||||
ProjectsFolder = Path.Combine(vaultRoot, "Projects"),
|
||||
DictationWordsPath = Path.Combine(vaultRoot, "Meetings", "dictation-words.md")
|
||||
}
|
||||
}),
|
||||
NullLogger<MarkdownMeetingNoteStore>.Instance);
|
||||
|
||||
return (vaultRoot, store);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user