?? ?? ?? ???? PPTX ??? ? ?? ??
?? ?? ??? PPTX/DOCX/XLSX/HTML ???? ? ?????, PPTX? ???? ??? ? ???? ?? ???? ? ??? ?? ?? ???? ????. ?? ????: - ExcelSkill? conditional_formats? ??? ?? ???? ??? ? ?????? OpenXML? ?? ???? workbook quality review? ?? - DocxSkill? style_map? ??? ???? ??/??/?? ???? ?? ?? ParagraphStyleId? ?? - HtmlSkill? print_header/print_footer ?? ?? ???? ???? ArtifactQualityReviewService? ?? ?? ?? ???? ?? - PptxTemplatePackRegistry? PptxSkill template_pack ????? ??? strategy/board/pmo/finance/sales/operating_model ??? ??? ?? ?? ?? ??? ?? - ?????, ????, ?? ???, ??? ?? ?? ?? ???? ???? ?? ?? ?? ???? ???? ???? ?? ?? ??: - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_next_doc_ppt\\ -p:IntermediateOutputPath=obj\\verify_next_doc_ppt\\ => ?? 0 / ?? 0 - dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|ExcelSkillDataValidationTests|ExcelSkillConditionalFormattingTests|ExcelSkillExecutiveSummaryLinkTests|ExcelSkillSummarySheetTests|DocxSkillTemplateFeaturesTests|DocxSkillStyleMapTests|HtmlSkillConsultingSectionsTests|HtmlSkillPrintFrameTests|DocumentAssemblerDocxFeaturesTests|PptxSkillConsultingDeckTests|PptxSkillAutoRepairTests|PptxSkillTemplatePackTests" -p:OutputPath=bin\\verify_next_doc_ppt_tests\\ -p:IntermediateOutputPath=obj\\verify_next_doc_ppt_tests\\ => ?? 15
This commit is contained in:
@@ -24,8 +24,10 @@ public class ArtifactQualityReviewServiceTests
|
||||
var review = ArtifactQualityReviewService.ReviewHtml("Board Report", html, hasCover: true, hasTableOfContents: true, printReady: true);
|
||||
|
||||
review.Score.Should().BeGreaterThan(75);
|
||||
review.Strengths.Should().Contain(s => s.Contains("커버") || s.Contains("목차"));
|
||||
review.Issues.Should().NotContain(i => i.Severity == ArtifactReviewSeverity.Critical);
|
||||
review.Strengths.Should().Contain(strength =>
|
||||
strength.Contains("cover", StringComparison.OrdinalIgnoreCase) ||
|
||||
strength.Contains("contents", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().NotContain(issue => issue.Severity == ArtifactReviewSeverity.Critical);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -48,8 +50,8 @@ public class ArtifactQualityReviewServiceTests
|
||||
false,
|
||||
false));
|
||||
|
||||
review.Issues.Should().Contain(i => i.Message.Contains("Executive Summary"));
|
||||
review.Issues.Should().Contain(i => i.Message.Contains("권고안"));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("Executive Summary", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("Recommendation", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -63,11 +65,12 @@ public class ArtifactQualityReviewServiceTests
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false));
|
||||
|
||||
review.Issues.Should().Contain(i => i.Message.Contains("요약 시트"));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("summary sheet", StringComparison.OrdinalIgnoreCase));
|
||||
review.Score.Should().BeLessThan(80);
|
||||
}
|
||||
}
|
||||
|
||||
106
src/AxCopilot.Tests/Services/DocxSkillStyleMapTests.cs
Normal file
106
src/AxCopilot.Tests/Services/DocxSkillStyleMapTests.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using AxCopilot.Services.Agent;
|
||||
using DocumentFormat.OpenXml.Packaging;
|
||||
using DocumentFormat.OpenXml.Wordprocessing;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace AxCopilot.Tests.Services;
|
||||
|
||||
public class DocxSkillStyleMapTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WithStyleMap_ShouldApplyTemplateParagraphStyles()
|
||||
{
|
||||
var workDir = Path.Combine(Path.GetTempPath(), "ax-docx-stylemap-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(workDir);
|
||||
|
||||
try
|
||||
{
|
||||
var templatePath = Path.Combine(workDir, "style-template.docx");
|
||||
using (var template = WordprocessingDocument.Create(templatePath, DocumentFormat.OpenXml.WordprocessingDocumentType.Document))
|
||||
{
|
||||
var mainPart = template.AddMainDocumentPart();
|
||||
mainPart.Document = new Document(new Body(new Paragraph(new Run(new Text("Template Root")))));
|
||||
|
||||
var stylePart = mainPart.AddNewPart<StyleDefinitionsPart>();
|
||||
stylePart.Styles = new Styles(
|
||||
CreateParagraphStyle("CustomTitle"),
|
||||
CreateParagraphStyle("CustomHeading1"),
|
||||
CreateParagraphStyle("CustomHeading2"),
|
||||
CreateParagraphStyle("CustomBody"));
|
||||
stylePart.Styles.Save();
|
||||
|
||||
mainPart.Document.Save();
|
||||
}
|
||||
|
||||
var tool = new DocxSkill();
|
||||
var context = new AgentContext
|
||||
{
|
||||
WorkFolder = workDir,
|
||||
Permission = "Auto",
|
||||
OperationMode = "external",
|
||||
};
|
||||
|
||||
var args = JsonDocument.Parse(
|
||||
"""
|
||||
{
|
||||
"path": "styled-brief.docx",
|
||||
"title": "Styled Brief",
|
||||
"template_path": "style-template.docx",
|
||||
"style_map": {
|
||||
"title": "CustomTitle",
|
||||
"heading1": "CustomHeading1",
|
||||
"heading2": "CustomHeading2",
|
||||
"body": "CustomBody"
|
||||
},
|
||||
"sections": [
|
||||
{ "heading": "Executive Summary", "body": "Body line one.\nBody line two.", "level": 1 },
|
||||
{ "heading": "Detail", "body": "Detail text.", "level": 2 }
|
||||
]
|
||||
}
|
||||
""").RootElement;
|
||||
|
||||
var result = await tool.ExecuteAsync(args, context, CancellationToken.None);
|
||||
|
||||
result.Success.Should().BeTrue();
|
||||
var outputPath = Path.Combine(workDir, "styled-brief.docx");
|
||||
File.Exists(outputPath).Should().BeTrue();
|
||||
|
||||
using var doc = WordprocessingDocument.Open(outputPath, false);
|
||||
var paragraphs = doc.MainDocumentPart!.Document.Body!.Descendants<Paragraph>().ToList();
|
||||
|
||||
paragraphs.First(paragraph => paragraph.InnerText == "Styled Brief")
|
||||
.ParagraphProperties!.ParagraphStyleId!.Val!.Value.Should().Be("CustomTitle");
|
||||
paragraphs.First(paragraph => paragraph.InnerText == "Executive Summary")
|
||||
.ParagraphProperties!.ParagraphStyleId!.Val!.Value.Should().Be("CustomHeading1");
|
||||
paragraphs.First(paragraph => paragraph.InnerText == "Detail")
|
||||
.ParagraphProperties!.ParagraphStyleId!.Val!.Value.Should().Be("CustomHeading2");
|
||||
paragraphs.First(paragraph => paragraph.InnerText == "Body line one.")
|
||||
.ParagraphProperties!.ParagraphStyleId!.Val!.Value.Should().Be("CustomBody");
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(workDir))
|
||||
Directory.Delete(workDir, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Style CreateParagraphStyle(string styleId)
|
||||
{
|
||||
return new Style
|
||||
{
|
||||
Type = StyleValues.Paragraph,
|
||||
StyleId = styleId,
|
||||
CustomStyle = true,
|
||||
StyleName = new StyleName { Val = styleId },
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using AxCopilot.Services.Agent;
|
||||
using DocumentFormat.OpenXml.Packaging;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace AxCopilot.Tests.Services;
|
||||
|
||||
public class ExcelSkillConditionalFormattingTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WithConditionalFormats_ShouldPersistFormattingRules()
|
||||
{
|
||||
var workDir = Path.Combine(Path.GetTempPath(), "ax-xlsx-conditional-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(workDir);
|
||||
|
||||
try
|
||||
{
|
||||
var tool = new ExcelSkill();
|
||||
var context = new AgentContext
|
||||
{
|
||||
WorkFolder = workDir,
|
||||
Permission = "Auto",
|
||||
OperationMode = "external",
|
||||
};
|
||||
|
||||
var args = JsonDocument.Parse(
|
||||
"""
|
||||
{
|
||||
"path": "conditional.xlsx",
|
||||
"sheet_name": "Tracker",
|
||||
"headers": ["Metric", "Score", "Trend"],
|
||||
"rows": [
|
||||
["Margin", 42, 12],
|
||||
["Retention", 61, 8],
|
||||
["Cycle Time", 19, -3]
|
||||
],
|
||||
"conditional_formats": [
|
||||
{ "range": "B2:B10", "type": "color_scale", "low": "FEE2E2", "mid": "FEF3C7", "high": "DCFCE7" },
|
||||
{ "range": "C2:C10", "type": "data_bar", "color": "2563EB" }
|
||||
]
|
||||
}
|
||||
""").RootElement;
|
||||
|
||||
var result = await tool.ExecuteAsync(args, context, CancellationToken.None);
|
||||
|
||||
result.Success.Should().BeTrue();
|
||||
result.Output.Should().Contain("Quality score");
|
||||
|
||||
var outputPath = Path.Combine(workDir, "conditional.xlsx");
|
||||
File.Exists(outputPath).Should().BeTrue();
|
||||
|
||||
using var doc = SpreadsheetDocument.Open(outputPath, false);
|
||||
var firstSheet = doc.WorkbookPart!.Workbook.Sheets!.Elements<Sheet>().First();
|
||||
var worksheetPart = (WorksheetPart)doc.WorkbookPart.GetPartById(firstSheet.Id!);
|
||||
|
||||
worksheetPart.Worksheet.Elements<ConditionalFormatting>().Count().Should().Be(2);
|
||||
var ruleTypes = worksheetPart.Worksheet.Descendants<ConditionalFormattingRule>()
|
||||
.Select(rule => rule.Type?.Value)
|
||||
.ToList();
|
||||
ruleTypes.Should().Contain(ConditionalFormatValues.ColorScale);
|
||||
ruleTypes.Should().Contain(ConditionalFormatValues.DataBar);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(workDir))
|
||||
Directory.Delete(workDir, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class ExcelSkillDataValidationTests
|
||||
var result = await tool.ExecuteAsync(args, context, CancellationToken.None);
|
||||
|
||||
result.Success.Should().BeTrue();
|
||||
result.Output.Should().Contain("점수");
|
||||
result.Output.Should().Contain("Quality score");
|
||||
|
||||
var outputPath = Path.Combine(workDir, "validated.xlsx");
|
||||
File.Exists(outputPath).Should().BeTrue();
|
||||
|
||||
62
src/AxCopilot.Tests/Services/HtmlSkillPrintFrameTests.cs
Normal file
62
src/AxCopilot.Tests/Services/HtmlSkillPrintFrameTests.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using AxCopilot.Services.Agent;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace AxCopilot.Tests.Services;
|
||||
|
||||
public class HtmlSkillPrintFrameTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WithPrintHeaderAndFooter_ShouldRenderPrintFrame()
|
||||
{
|
||||
var workDir = Path.Combine(Path.GetTempPath(), "ax-html-printframe-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(workDir);
|
||||
|
||||
try
|
||||
{
|
||||
var tool = new HtmlSkill();
|
||||
var context = new AgentContext
|
||||
{
|
||||
WorkFolder = workDir,
|
||||
Permission = "Auto",
|
||||
OperationMode = "external",
|
||||
};
|
||||
|
||||
var args = JsonDocument.Parse(
|
||||
"""
|
||||
{
|
||||
"path": "board-report.html",
|
||||
"title": "Board Report",
|
||||
"print": true,
|
||||
"print_header": "Board Review",
|
||||
"print_footer": "Confidential",
|
||||
"body": "<h2>Executive Summary</h2><p>Summary text with enough detail to qualify as a printable executive report.</p><h2>Recommendation</h2><p>Approve phase 1.</p><h2>Appendix</h2><p>Evidence notes.</p>"
|
||||
}
|
||||
""").RootElement;
|
||||
|
||||
var result = await tool.ExecuteAsync(args, context, CancellationToken.None);
|
||||
|
||||
result.Success.Should().BeTrue();
|
||||
result.Output.Should().Contain("Quality score");
|
||||
|
||||
var html = File.ReadAllText(Path.Combine(workDir, "board-report.html"));
|
||||
html.Should().Contain("print-header");
|
||||
html.Should().Contain("print-footer");
|
||||
html.Should().Contain("Board Review");
|
||||
html.Should().Contain("Confidential");
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(workDir))
|
||||
Directory.Delete(workDir, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/AxCopilot.Tests/Services/PptxSkillTemplatePackTests.cs
Normal file
66
src/AxCopilot.Tests/Services/PptxSkillTemplatePackTests.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using AxCopilot.Services.Agent;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace AxCopilot.Tests.Services;
|
||||
|
||||
public class PptxSkillTemplatePackTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WithTemplatePack_ShouldReportSelectedPack()
|
||||
{
|
||||
var workDir = Path.Combine(Path.GetTempPath(), "ax-pptx-pack-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(workDir);
|
||||
|
||||
try
|
||||
{
|
||||
var context = new AgentContext
|
||||
{
|
||||
WorkFolder = workDir,
|
||||
Permission = "Auto",
|
||||
OperationMode = "external",
|
||||
};
|
||||
|
||||
var tool = new PptxSkill();
|
||||
var args = JsonDocument.Parse(
|
||||
"""
|
||||
{
|
||||
"path": "board-pack-deck.pptx",
|
||||
"title": "Board Update",
|
||||
"template_pack": "board",
|
||||
"slides": [
|
||||
{
|
||||
"layout": "content",
|
||||
"title": "Current State",
|
||||
"body": "Margin improved\nDelivery risk is stable\nWorking capital is within plan"
|
||||
},
|
||||
{
|
||||
"layout": "recommendation",
|
||||
"title": "Recommendation",
|
||||
"recommendation": "Approve the next operating phase"
|
||||
}
|
||||
]
|
||||
}
|
||||
""").RootElement;
|
||||
|
||||
var result = await tool.ExecuteAsync(args, context, CancellationToken.None);
|
||||
|
||||
result.Success.Should().BeTrue();
|
||||
result.Output.Should().Contain("Template pack: board");
|
||||
File.Exists(Path.Combine(workDir, "board-pack-deck.pptx")).Should().BeTrue();
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(workDir))
|
||||
Directory.Delete(workDir, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user