mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Step 2 in renaming Orchard.Scripting to Orchard.Scripting.Dlr
--HG-- branch : dev rename : src/Orchard.Tests.Modules/Scripting/ScriptingTests.cs => src/Orchard.Tests.Modules/Scripting.Dlr/ScriptingTests.cs rename : src/Orchard.Tests.Modules/SimpleScripting/EvaluatorTests.cs => src/Orchard.Tests.Modules/Scripting/EvaluatorTests.cs rename : src/Orchard.Tests.Modules/SimpleScripting/ParserTests.cs => src/Orchard.Tests.Modules/Scripting/ParserTests.cs rename : src/Orchard.Tests.Modules/SimpleScripting/SimpleScriptingTests.cs => src/Orchard.Tests.Modules/Scripting/SimpleScriptingTests.cs rename : src/Orchard.Tests.Modules/SimpleScripting/TokenizerTests.cs => src/Orchard.Tests.Modules/Scripting/TokenizerTests.cs rename : src/Orchard.Web/Modules/Orchard.Scripting.Dlr/Orchard.Scripting.csproj => src/Orchard.Web/Modules/Orchard.Scripting.Dlr/Orchard.Scripting.Dlr.csproj
This commit is contained in:
102
src/Orchard.Tests.Modules/Scripting/EvaluatorTests.cs
Normal file
102
src/Orchard.Tests.Modules/Scripting/EvaluatorTests.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Widgets.SimpleScripting.Compiler;
|
||||
|
||||
namespace Orchard.Tests.Modules.Scripting {
|
||||
[TestFixture]
|
||||
public class EvaluatorTests {
|
||||
[Test]
|
||||
public void EvaluateSimpleConstant() {
|
||||
var result = EvaluateSimpleExpression("true and true");
|
||||
Assert.That(result.IsError, Is.False);
|
||||
Assert.That(result.Value, Is.EqualTo(true));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EvaluateInvalidBooleanExpression() {
|
||||
var result = EvaluateSimpleExpression("true and 1");
|
||||
Assert.That(result.IsError, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EvaluateBooleanExpression() {
|
||||
var result = EvaluateSimpleExpression("not true");
|
||||
Assert.That(result.IsError, Is.False);
|
||||
Assert.That(result.BoolValue, Is.EqualTo(false));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EvaluateSimpleArithmetic() {
|
||||
var result = EvaluateSimpleExpression("1 + 2 * 3 - 6 / 2");
|
||||
Assert.That(result.IsError, Is.False);
|
||||
Assert.That(result.Value, Is.EqualTo(4));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EvaluateSimpleMethodCall() {
|
||||
var result = EvaluateSimpleExpression("print 1 + 2 * 3 - 6 / 2",
|
||||
(m, args) => (m == "print") ? (int)args[0] * 2 : 0);
|
||||
Assert.That(result.IsError, Is.False);
|
||||
Assert.That(result.Value, Is.EqualTo(4 * 2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EvaluateSimpleMethodCall2() {
|
||||
var result = EvaluateSimpleExpression("foo 1 + bar 3",
|
||||
(m, args) =>
|
||||
(m == "foo") ? (int)args[0] * 2 :
|
||||
(m == "bar") ? (int)args[0] : 0);
|
||||
Assert.That(result.IsError, Is.False);
|
||||
Assert.That(result.Value, Is.EqualTo(2 * (1 + 3)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EvaluateSimpleMethodCall3() {
|
||||
var result = EvaluateSimpleExpression("foo(1) + bar(3)",
|
||||
(m, args) =>
|
||||
(m == "foo") ? (int)args[0] * 2 :
|
||||
(m == "bar") ? (int)args[0] : 0);
|
||||
Assert.That(result.IsError, Is.False);
|
||||
Assert.That(result.Value, Is.EqualTo(2 + 3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EvaluateSimpleMethodCall4() {
|
||||
var result = EvaluateSimpleExpression("foo",
|
||||
(m, args) => (m == "foo") ? true : false);
|
||||
Assert.That(result.IsError, Is.False);
|
||||
Assert.That(result.Value, Is.EqualTo(true));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EvaluateSimpleMethodCall5() {
|
||||
var result = EvaluateSimpleExpression("foo()",
|
||||
(m, args) => (m == "foo") ? true : false);
|
||||
Assert.That(result.IsError, Is.False);
|
||||
Assert.That(result.Value, Is.EqualTo(true));
|
||||
}
|
||||
|
||||
private EvaluationResult EvaluateSimpleExpression(string expression) {
|
||||
return EvaluateSimpleExpression(expression, (m, args) => null);
|
||||
}
|
||||
|
||||
private EvaluationResult EvaluateSimpleExpression(
|
||||
string expression, Func<string, IList<object>, object> methodInvocationCallback) {
|
||||
|
||||
var ast = new Parser(expression).Parse();
|
||||
foreach(var error in ast.GetErrors()) {
|
||||
Trace.WriteLine(string.Format("Error during parsing of '{0}': {1}", expression, error.Message));
|
||||
}
|
||||
Assert.That(ast.GetErrors().Any(), Is.False);
|
||||
var result = new Interpreter().Evalutate(new EvaluationContext {
|
||||
Tree = ast,
|
||||
MethodInvocationCallback = methodInvocationCallback
|
||||
});
|
||||
Trace.WriteLine(string.Format("Result of evaluation of '{0}': {1}", expression, result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
197
src/Orchard.Tests.Modules/Scripting/ParserTests.cs
Normal file
197
src/Orchard.Tests.Modules/Scripting/ParserTests.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Widgets.SimpleScripting.Ast;
|
||||
using Orchard.Widgets.SimpleScripting.Compiler;
|
||||
|
||||
namespace Orchard.Tests.Modules.Scripting {
|
||||
[TestFixture]
|
||||
public class ParserTests {
|
||||
[Test]
|
||||
public void ParserShouldUnderstandConstantExpressions() {
|
||||
var tree = new Parser("true").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"const", true,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldUnderstandBinaryExpressions() {
|
||||
var tree = new Parser("true+true").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"binop", TokenKind.Plus,
|
||||
"const", true,
|
||||
"const", true,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldUnderstandCommandExpressions() {
|
||||
var tree = new Parser("print 'foo', 'bar'").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"call", TokenKind.Identifier, "print",
|
||||
"const", "foo",
|
||||
"const", "bar",
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldUnderstandCallExpressions() {
|
||||
var tree = new Parser("print('foo', 'bar')").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"call", TokenKind.Identifier, "print",
|
||||
"const", "foo",
|
||||
"const", "bar",
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldUnderstandCallExpressions2() {
|
||||
var tree = new Parser("print 1+2").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"call", TokenKind.Identifier, "print",
|
||||
"binop", TokenKind.Plus,
|
||||
"const", 1,
|
||||
"const", 2,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldUnderstandOperatorPrecedence() {
|
||||
var tree = new Parser("1+2*3").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"binop", TokenKind.Plus,
|
||||
"const", 1,
|
||||
"binop", TokenKind.Mul,
|
||||
"const", 2,
|
||||
"const", 3,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldUnderstandOperatorPrecedence2() {
|
||||
var tree = new Parser("1*2+3").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"binop", TokenKind.Plus,
|
||||
"binop", TokenKind.Mul,
|
||||
"const", 1,
|
||||
"const", 2,
|
||||
"const", 3,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldUnderstandOperatorPrecedence3() {
|
||||
var tree = new Parser("not true or true").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"binop", TokenKind.Or,
|
||||
"unop", TokenKind.Not,
|
||||
"const", true,
|
||||
"const", true,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldUnderstandOperatorPrecedence4() {
|
||||
var tree = new Parser("not (true or true)").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"unop", TokenKind.Not,
|
||||
"binop", TokenKind.Or,
|
||||
"const", true,
|
||||
"const", true,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldUnderstandParenthesis() {
|
||||
var tree = new Parser("1*(2+3)").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"binop", TokenKind.Mul,
|
||||
"const", 1,
|
||||
"binop", TokenKind.Plus,
|
||||
"const", 2,
|
||||
"const", 3,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldUnderstandComplexExpressions() {
|
||||
var tree = new Parser("not 1 * (2 / 4 * 6 + (3))").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"unop", TokenKind.Not,
|
||||
"binop", TokenKind.Mul,
|
||||
"const", 1,
|
||||
"binop", TokenKind.Plus,
|
||||
"binop", TokenKind.Div,
|
||||
"const", 2,
|
||||
"binop", TokenKind.Mul,
|
||||
"const", 4,
|
||||
"const", 6,
|
||||
"const", 3,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserShouldContainErrorExpressions() {
|
||||
var tree = new Parser("1 + not 3").Parse();
|
||||
CheckTree(tree, new object[] {
|
||||
"binop", TokenKind.Plus,
|
||||
"const", 1,
|
||||
"error",
|
||||
});
|
||||
}
|
||||
|
||||
private void CheckTree(AbstractSyntaxTree tree, object[] objects) {
|
||||
Assert.That(tree, Is.Not.Null);
|
||||
Assert.That(tree.Root, Is.Not.Null);
|
||||
|
||||
int index = 0;
|
||||
CheckExpression(tree.Root, 0, objects, ref index);
|
||||
Assert.That(index, Is.EqualTo(objects.Length));
|
||||
}
|
||||
|
||||
private void CheckExpression(AstNode astNode, int indent, object[] objects, ref int index) {
|
||||
var exprName = (string)objects[index++];
|
||||
Type type = null;
|
||||
switch (exprName) {
|
||||
case "const":
|
||||
type = typeof(ConstantAstNode);
|
||||
break;
|
||||
case "binop":
|
||||
type = typeof(BinaryAstNode);
|
||||
break;
|
||||
case "unop":
|
||||
type = typeof(UnaryAstNode);
|
||||
break;
|
||||
case "call":
|
||||
type = typeof(MethodCallAstNode);
|
||||
break;
|
||||
case "error":
|
||||
type = typeof(ErrorAstNode);
|
||||
break;
|
||||
}
|
||||
|
||||
Trace.WriteLine(string.Format("{0}: {1}{2} (Current: {3})", indent, new string(' ', indent * 2), type.Name, astNode));
|
||||
|
||||
Assert.That(astNode.GetType(), Is.EqualTo(type));
|
||||
|
||||
if (exprName == "const") {
|
||||
Assert.That((astNode as ConstantAstNode).Value, Is.EqualTo(objects[index++]));
|
||||
}
|
||||
else if (exprName == "binop") {
|
||||
Assert.That((astNode as BinaryAstNode).Operator.Kind, Is.EqualTo(objects[index++]));
|
||||
}
|
||||
else if (exprName == "unop") {
|
||||
Assert.That((astNode as UnaryAstNode).Operator.Kind, Is.EqualTo(objects[index++]));
|
||||
}
|
||||
else if (exprName == "call") {
|
||||
Assert.That((astNode as MethodCallAstNode).Token.Kind, Is.EqualTo(objects[index++]));
|
||||
Assert.That((astNode as MethodCallAstNode).Token.Value, Is.EqualTo(objects[index++]));
|
||||
}
|
||||
|
||||
foreach (var child in astNode.Children) {
|
||||
CheckExpression(child, indent + 1, objects, ref index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,120 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Autofac;
|
||||
using ClaySharp;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Scripting.Services;
|
||||
using Path = Bleroy.FluentPath.Path;
|
||||
|
||||
namespace Orchard.Tests.Modules.Scripting {
|
||||
[TestFixture]
|
||||
public class ScriptingTests {
|
||||
private IContainer _container;
|
||||
private IScriptingRuntime _scriptingRuntime;
|
||||
private IScriptingManager _scriptingManager;
|
||||
private readonly Path _tempFixtureFolderName = Path.Get(System.IO.Path.GetTempPath()).Combine("Orchard.Tests.Modules.Scripting");
|
||||
private Path _tempFolderName;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterType<RubyScriptingRuntime>().As<IScriptingRuntime>();
|
||||
builder.RegisterType<ScriptingManager>().As<IScriptingManager>();
|
||||
_container = builder.Build();
|
||||
_scriptingRuntime = _container.Resolve<IScriptingRuntime>();
|
||||
_scriptingManager = _container.Resolve<IScriptingManager>();
|
||||
_tempFolderName = _tempFixtureFolderName.Combine(System.IO.Path.GetRandomFileName());
|
||||
try {
|
||||
_tempFolderName.Delete();
|
||||
}
|
||||
catch { }
|
||||
_tempFolderName.CreateDirectory();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Term() {
|
||||
try { _tempFixtureFolderName.Delete(true); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateScopeReturnsWorkingScope() {
|
||||
var scope = _scriptingRuntime.CreateScope();
|
||||
|
||||
Assert.IsNotNull(scope);
|
||||
scope.SetVariable("alpha", 42);
|
||||
Assert.That(scope.GetVariable("alpha"), Is.EqualTo(42));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScriptingManagerCanGetAndSetRubyVariables() {
|
||||
_scriptingManager.SetVariable("foo", 42);
|
||||
Assert.That(_scriptingManager.GetVariable("foo"), Is.EqualTo(42));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScriptingManagerCanEvalExpression() {
|
||||
_scriptingManager.SetVariable("foo", 21);
|
||||
Assert.That(_scriptingManager.ExecuteExpression("foo + 21"), Is.EqualTo(42));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScriptCanBeExecutedAndScopeProvidesContextIsolation() {
|
||||
var scriptManager1 = new ScriptingManager(_scriptingRuntime);
|
||||
var scriptManager2 = new ScriptingManager(_scriptingRuntime);
|
||||
|
||||
scriptManager1.SetVariable("foo", 1);
|
||||
scriptManager2.SetVariable("foo", 2);
|
||||
|
||||
var result1 = scriptManager1.ExecuteExpression("3 + foo");
|
||||
var result2 = scriptManager2.ExecuteExpression("3 + foo");
|
||||
|
||||
Assert.That(result1, Is.EqualTo(4));
|
||||
Assert.That(result2, Is.EqualTo(5));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScriptingManagerCanExecuteFile() {
|
||||
var targetPath = _tempFolderName.Combine("SampleMethodDefinition.rb");
|
||||
File.WriteAllText(targetPath, "def f\r\nreturn 32\r\nend\r\n");
|
||||
_scriptingManager.ExecuteFile(targetPath);
|
||||
Assert.That(_scriptingManager.ExecuteExpression("f / 4"), Is.EqualTo(8));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void CanDeclareCallbackOnGlobalMethod() {
|
||||
_scriptingManager.SetVariable("x", new Clay(new ReturnMethodNameLengthBehavior()));
|
||||
|
||||
Assert.That(_scriptingManager.ExecuteExpression("3 + x.foo()"), Is.EqualTo(6));
|
||||
}
|
||||
|
||||
|
||||
public class ReturnMethodNameLengthBehavior : ClayBehavior {
|
||||
public override object InvokeMemberMissing(Func<object> proceed, object self, string name, INamedEnumerable<object> args) {
|
||||
Trace.WriteLine("Returning length of " + name);
|
||||
return name.Length;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanDeclareCallbackOnInstanceEvalWithFile() {
|
||||
var targetPath = _tempFolderName.Combine("CallbackOnInstanceEval.rb");
|
||||
File.WriteAllText(targetPath, "class ExecContext\r\ndef initialize(callbacks)\r\n@callbacks = callbacks;\r\nend\r\ndef execute(text)\r\ninstance_eval(text.to_s);\r\nend\r\ndef method_missing(name, *args, &block)\r\n@callbacks.send(name, args, &block);\r\nend\r\nend\r\ndef execute(&block)\r\nExecContext.new(callbacks).instance_eval(&block);\r\nend\r\n");
|
||||
_scriptingManager.ExecuteFile(targetPath);
|
||||
_scriptingManager.SetVariable("callbacks", new CallbackApi());
|
||||
|
||||
Assert.That(_scriptingManager.ExecuteExpression("execute { 1 + hello + world('yep') }"), Is.EqualTo(11));
|
||||
}
|
||||
|
||||
public class CallbackApi {
|
||||
public object send(string name, IList<object> args) {
|
||||
Trace.WriteLine("Returning length of method " + name);
|
||||
return name.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
31
src/Orchard.Tests.Modules/Scripting/SimpleScriptingTests.cs
Normal file
31
src/Orchard.Tests.Modules/Scripting/SimpleScriptingTests.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Tests.Stubs;
|
||||
using Orchard.Widgets.Services;
|
||||
using Orchard.Widgets.SimpleScripting;
|
||||
|
||||
namespace Orchard.Tests.Modules.Scripting {
|
||||
[TestFixture]
|
||||
public class SimpleScriptingTests {
|
||||
[Test]
|
||||
public void EngineThrowsSyntaxErrors() {
|
||||
var engine = new ScriptingEngine(Enumerable.Empty<IRuleProvider>(), new StubCacheManager());
|
||||
Assert.That(() => engine.Matches("true+"), Throws.Exception);
|
||||
}
|
||||
[Test]
|
||||
public void EngineThrowsEvalErrors() {
|
||||
var engine = new ScriptingEngine(Enumerable.Empty<IRuleProvider>(), new StubCacheManager());
|
||||
Assert.That(() => engine.Matches("1 + 1"), Throws.Exception);
|
||||
}
|
||||
[Test]
|
||||
public void EngineUnderstandsPrimitiveValues() {
|
||||
var engine = new ScriptingEngine(Enumerable.Empty<IRuleProvider>(), new StubCacheManager());
|
||||
Assert.That(engine.Matches("true"), Is.True);
|
||||
}
|
||||
[Test]
|
||||
public void EngineUnderstandsPrimitiveValues2() {
|
||||
var engine = new ScriptingEngine(Enumerable.Empty<IRuleProvider>(), new StubCacheManager());
|
||||
Assert.That(engine.Matches("true and true"), Is.True);
|
||||
}
|
||||
}
|
||||
}
|
76
src/Orchard.Tests.Modules/Scripting/TokenizerTests.cs
Normal file
76
src/Orchard.Tests.Modules/Scripting/TokenizerTests.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using NUnit.Framework;
|
||||
using Orchard.Widgets.SimpleScripting.Compiler;
|
||||
|
||||
namespace Orchard.Tests.Modules.Scripting {
|
||||
[TestFixture]
|
||||
public class TokenizerTests {
|
||||
|
||||
[Test]
|
||||
public void LexerShouldProcessSingleQuotedStringLiteral() {
|
||||
TestStringLiteral(@"'toto'", @"toto", TokenKind.SingleQuotedStringLiteral);
|
||||
TestStringLiteral(@"'to\'to'", @"to'to", TokenKind.SingleQuotedStringLiteral);
|
||||
TestStringLiteral(@"'to\\to'", @"to\to", TokenKind.SingleQuotedStringLiteral);
|
||||
TestStringLiteral(@"'to\ato'", @"to\ato", TokenKind.SingleQuotedStringLiteral);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LexerShouldProcessStringLiteral() {
|
||||
TestStringLiteral(@"""toto""", @"toto", TokenKind.StringLiteral);
|
||||
TestStringLiteral(@"""to\'to""", @"to'to", TokenKind.StringLiteral);
|
||||
TestStringLiteral(@"""to\\to""", @"to\to", TokenKind.StringLiteral);
|
||||
TestStringLiteral(@"""to\ato""", @"toato", TokenKind.StringLiteral);
|
||||
}
|
||||
|
||||
private void TestStringLiteral(string value, string expected, TokenKind expectedTokenKind) {
|
||||
var lexer = new Tokenizer(value);
|
||||
var token1 = lexer.NextToken();
|
||||
Assert.That(token1.Kind, Is.EqualTo(expectedTokenKind));
|
||||
Assert.That(token1.Value, Is.EqualTo(expected));
|
||||
|
||||
var token2 = lexer.NextToken();
|
||||
Assert.That(token2.Kind, Is.EqualTo(TokenKind.Eof));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LexerShouldProcessReservedWords() {
|
||||
TestReservedWord("true", true, TokenKind.True);
|
||||
TestReservedWord("false", false, TokenKind.False);
|
||||
TestReservedWord("not", null, TokenKind.Not);
|
||||
TestReservedWord("and", null, TokenKind.And);
|
||||
TestReservedWord("or", null, TokenKind.Or);
|
||||
}
|
||||
|
||||
private void TestReservedWord(string expression, object value, TokenKind expectedTokenKind) {
|
||||
var lexer = new Tokenizer(expression);
|
||||
var token1 = lexer.NextToken();
|
||||
Assert.That(token1.Kind, Is.EqualTo(expectedTokenKind));
|
||||
Assert.That(token1.Value, Is.EqualTo(value));
|
||||
|
||||
var token2 = lexer.NextToken();
|
||||
Assert.That(token2.Kind, Is.EqualTo(TokenKind.Eof));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LexerShouldProcesSequenceOfTokens() {
|
||||
CheckTokenSequence("true false", TokenKind.True, TokenKind.False);
|
||||
CheckTokenSequence("true toto false", TokenKind.True, TokenKind.Identifier, TokenKind.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LexerShouldProcesSequenceOfTokens2() {
|
||||
CheckTokenSequence("1+2*3", TokenKind.Integer, TokenKind.Plus, TokenKind.Integer, TokenKind.Mul, TokenKind.Integer);
|
||||
}
|
||||
|
||||
|
||||
private void CheckTokenSequence(string expression, params TokenKind[] tokenKinds) {
|
||||
var lexer = new Tokenizer(expression);
|
||||
foreach (var kind in tokenKinds) {
|
||||
var token = lexer.NextToken();
|
||||
Assert.That(token.Kind, Is.EqualTo(kind));
|
||||
}
|
||||
|
||||
var token2 = lexer.NextToken();
|
||||
Assert.That(token2.Kind, Is.EqualTo(TokenKind.Eof));
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user