final receipt update

This commit is contained in:
EugeneTes
2026-01-22 11:09:38 +01:00
parent 9fbc61dede
commit fcb192b797
31 changed files with 2679 additions and 655 deletions

View File

@@ -56,8 +56,8 @@ public class InterpreterLoopTests
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, """{"Items": ["A", "B"]}""");
Assert.Contains(commands, c => c.Text == "0");
Assert.Contains(commands, c => c.Text == "1");
Assert.Contains(commands, c => c.Text == "0:A");
Assert.Contains(commands, c => c.Text == "1:B");
}
[Fact]
@@ -67,8 +67,8 @@ public class InterpreterLoopTests
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, """{"Items": ["A", "B"]}""");
Assert.Contains(commands, c => c.Text == "1");
Assert.Contains(commands, c => c.Text == "2");
Assert.Contains(commands, c => c.Text == "1. A");
Assert.Contains(commands, c => c.Text == "2. B");
}
[Fact]
@@ -78,9 +78,7 @@ public class InterpreterLoopTests
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, """{"Items": ["A", "B", "C"]}""");
var firstCmds = commands.Where(c => c.Text.Contains("First")).ToList();
Assert.Single(firstCmds);
Assert.Contains(commands, c => c.Text == "A");
Assert.Contains(commands, c => c.Text == "First: A");
}
[Fact]
@@ -90,8 +88,7 @@ public class InterpreterLoopTests
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, """{"Items": ["A", "B", "C"]}""");
Assert.Contains(commands, c => c.Text.Contains("Last"));
Assert.Contains(commands, c => c.Text == "C");
Assert.Contains(commands, c => c.Text == "Last: C");
}
[Fact]
@@ -115,9 +112,8 @@ public class InterpreterLoopTests
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, """{"Title": "List", "Items": ["A", "B"]}""");
Assert.Contains(commands, c => c.Text == "List");
Assert.Contains(commands, c => c.Text == "A");
Assert.Contains(commands, c => c.Text == "B");
Assert.Contains(commands, c => c.Text == "List: A");
Assert.Contains(commands, c => c.Text == "List: B");
}
[Fact]

View File

@@ -102,4 +102,105 @@ public class InterpreterRowTests
Assert.NotNull(rowCmd);
Assert.Equal(30, rowCmd.Text.Length);
}
[Fact]
public void Interpret_Row_WithBoldStyle_SetsBold()
{
var template = Parse("@row bold\n|20|Name|10,right|Price\n@endrow");
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, "{}");
var rowCmd = commands.FirstOrDefault(c => c.Text.Contains("Name") && c.Text.Contains("Price"));
Assert.NotNull(rowCmd);
Assert.True(rowCmd.IsBold);
}
[Fact]
public void Interpret_Row_WithBigStyle_SetsBig()
{
var template = Parse("@row big\n|12|Name|6,right|Price\n@endrow");
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, "{}");
var rowCmd = commands.FirstOrDefault(c => c.Text.Contains("Name") && c.Text.Contains("Price"));
Assert.NotNull(rowCmd);
Assert.True(rowCmd.IsBig);
}
[Fact]
public void Interpret_Row_WithTallStyle_SetsTall()
{
var template = Parse("@row tall\n|20|Name|10,right|Price\n@endrow");
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, "{}");
var rowCmd = commands.FirstOrDefault(c => c.Text.Contains("Name") && c.Text.Contains("Price"));
Assert.NotNull(rowCmd);
Assert.True(rowCmd.IsTall);
}
[Fact]
public void Interpret_Row_WithMultipleStyles_AppliesAll()
{
var template = Parse("@row bold, big\n|12|Name|6,right|Price\n@endrow");
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, "{}");
var rowCmd = commands.FirstOrDefault(c => c.Text.Contains("Name") && c.Text.Contains("Price"));
Assert.NotNull(rowCmd);
Assert.True(rowCmd.IsBold);
Assert.True(rowCmd.IsBig);
}
[Fact]
public void Interpret_Row_WithRedStyle_OnSupportedPrinter_SetsRed()
{
var redProfile = new PrinterProfile("test", "Test Printer", 48, 24, SupportsRed: true);
var template = Parse("@row red\n|20|Warning|10,right|!\n@endrow");
var interpreter = new TemplateInterpreter(redProfile);
var commands = interpreter.Interpret(template, "{}");
var rowCmd = commands.FirstOrDefault(c => c.Text.Contains("Warning"));
Assert.NotNull(rowCmd);
Assert.True(rowCmd.IsRed);
}
[Fact]
public void Interpret_Row_WithRedStyle_OnUnsupportedPrinter_DoesNotSetRed()
{
var template = Parse("@row red\n|20|Warning|10,right|!\n@endrow");
var interpreter = new TemplateInterpreter(_profile); // _profile has supportsRed: false
var commands = interpreter.Interpret(template, "{}");
var rowCmd = commands.FirstOrDefault(c => c.Text.Contains("Warning"));
Assert.NotNull(rowCmd);
Assert.False(rowCmd.IsRed);
}
[Fact]
public void Interpret_Row_WithoutStyles_NoStylesApplied()
{
var template = Parse("@row\n|20|Name|10,right|Price\n@endrow");
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, "{}");
var rowCmd = commands.FirstOrDefault(c => c.Text.Contains("Name") && c.Text.Contains("Price"));
Assert.NotNull(rowCmd);
Assert.False(rowCmd.IsBold);
Assert.False(rowCmd.IsBig);
Assert.False(rowCmd.IsTall);
Assert.False(rowCmd.IsRed);
}
[Fact]
public void Interpret_Row_WithSpacingStyle_SetsLineSpacing()
{
var template = Parse("@row spacing:50\n|20|Name|10,right|Price\n@endrow");
var interpreter = new TemplateInterpreter(_profile);
var commands = interpreter.Interpret(template, "{}");
var rowCmd = commands.FirstOrDefault(c => c.Text.Contains("Name") && c.Text.Contains("Price"));
Assert.NotNull(rowCmd);
Assert.Equal(50, rowCmd.SetLineSpacing);
}
}

View File

@@ -216,4 +216,70 @@ Line 3";
}
#endregion
#region Comment lines should not produce empty lines
[Fact]
public void Tokenize_ConsecutiveCommentLines_ProduceNoNewLineTokens()
{
var lexer = new Lexer("@**@\n@**@\n@**@");
var result = lexer.Tokenize();
Assert.False(result.HasErrors);
// Should only have EOF token, no NewLine tokens for comment-only lines
Assert.DoesNotContain(result.Tokens, t => t.Type == TokenType.NewLine);
}
[Fact]
public void Tokenize_CommentLineBetweenContent_NoExtraNewLines()
{
var lexer = new Lexer("Line1\n@**@\nLine2");
var result = lexer.Tokenize();
Assert.False(result.HasErrors);
// Should have exactly 2 NewLine tokens (after Line1 and after Line2)
var newLineCount = result.Tokens.Count(t => t.Type == TokenType.NewLine);
Assert.Equal(2, newLineCount);
}
[Fact]
public void Tokenize_MultipleConsecutiveCommentLines_NoNewLines()
{
var lexer = new Lexer("Header\n@* comment 1 *@\n@* comment 2 *@\n@* comment 3 *@\nFooter");
var result = lexer.Tokenize();
Assert.False(result.HasErrors);
Assert.Contains(result.Tokens, t => t.Type == TokenType.Text && t.Value == "Header");
Assert.Contains(result.Tokens, t => t.Type == TokenType.Text && t.Value == "Footer");
// Should have exactly 2 NewLine tokens (after Header and after Footer)
var newLineCount = result.Tokens.Count(t => t.Type == TokenType.NewLine);
Assert.Equal(2, newLineCount);
}
[Fact]
public void Tokenize_EmptyLinesBetweenContent_ProducesNewLines()
{
var lexer = new Lexer("Line1\n\n\nLine2");
var result = lexer.Tokenize();
Assert.False(result.HasErrors);
// Should have 4 NewLine tokens (after Line1, after each empty line, after Line2)
var newLineCount = result.Tokens.Count(t => t.Type == TokenType.NewLine);
Assert.Equal(4, newLineCount);
}
[Fact]
public void Tokenize_EmptyLinesPreserved_CommentsRemoved()
{
var lexer = new Lexer("Header\n\n@* comment *@\n\nFooter");
var result = lexer.Tokenize();
Assert.False(result.HasErrors);
// Should have 4 NewLine tokens: after Header, after first empty line, after second empty line, after Footer
// The comment line should NOT produce a NewLine
var newLineCount = result.Tokens.Count(t => t.Type == TokenType.NewLine);
Assert.Equal(4, newLineCount);
}
#endregion
}