mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 21:27:40 +00:00
GUACAMOLE-615: Add more thorough unit tests for protocol parsing.
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.guacamole.protocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit test for GuacamoleParser. Verifies that parsing of the Guacamole
|
||||
* protocol works as required.
|
||||
*/
|
||||
public class GuacamoleInstructionTest {
|
||||
|
||||
/**
|
||||
* A single test case for verifying that Guacamole protocol implementations
|
||||
* correctly parse or encode Guacamole instructions.
|
||||
*/
|
||||
public static class TestCase extends GuacamoleInstruction {
|
||||
|
||||
/**
|
||||
* The full and correct Guacamole protocol representation of this
|
||||
* instruction.
|
||||
*/
|
||||
public final String UNPARSED;
|
||||
|
||||
/**
|
||||
* The opcode that should be present in the Guacamole instruction;
|
||||
*/
|
||||
public final String OPCODE;
|
||||
|
||||
/**
|
||||
* All arguments that should be present in the Guacamole instruction;
|
||||
*/
|
||||
public final List<String> ARGS;
|
||||
|
||||
/**
|
||||
* Creates a new TestCase representing the given Guacamole instruction.
|
||||
*
|
||||
* @param unparsed
|
||||
* The full and correct Guacamole protocol representation of this
|
||||
* instruction.
|
||||
*
|
||||
* @param opcode
|
||||
* The opcode of the Guacamole instruction.
|
||||
*
|
||||
* @param args
|
||||
* The arguments of the Guacamole instruction, if any.
|
||||
*/
|
||||
public TestCase(String unparsed, String opcode, String... args) {
|
||||
super(opcode, Arrays.copyOf(args, args.length));
|
||||
this.UNPARSED = unparsed;
|
||||
this.OPCODE = opcode;
|
||||
this.ARGS = Collections.unmodifiableList(Arrays.asList(args));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A single Unicode high surrogate character (any character between U+D800
|
||||
* and U+DB7F).
|
||||
*/
|
||||
public static final String HIGH_SURROGATE = "\uD802";
|
||||
|
||||
/**
|
||||
* A single Unicode low surrogate character (any character between U+DC00
|
||||
* and U+DFFF).
|
||||
*/
|
||||
public static final String LOW_SURROGATE = "\uDF00";
|
||||
|
||||
/**
|
||||
* A Unicode surrogate pair, consisting of a high and low surrogate.
|
||||
*/
|
||||
public static final String SURROGATE_PAIR = HIGH_SURROGATE + LOW_SURROGATE;
|
||||
|
||||
/**
|
||||
* A 4-character test string containing Unicode characters that require
|
||||
* multiple bytes when encoded as UTF-8, including at least one character
|
||||
* that is encoded as a surrogate pair in UTF-16.
|
||||
*/
|
||||
public static final String UTF8_MULTIBYTE = "\u72AC" + SURROGATE_PAIR + "z\u00C1";
|
||||
|
||||
/**
|
||||
* Pre-defined set of test cases for verifying Guacamole instructions are
|
||||
* correctly parsed and encoded.
|
||||
*/
|
||||
public static List<TestCase> TEST_CASES = Collections.unmodifiableList(Arrays.asList(
|
||||
|
||||
// Empty instruction
|
||||
new TestCase(
|
||||
"0.;",
|
||||
""
|
||||
),
|
||||
|
||||
// Instruction using basic Latin characters
|
||||
new TestCase(
|
||||
|
||||
"5.test2,"
|
||||
+ "10.hellohello,"
|
||||
+ "15.worldworldworld;",
|
||||
|
||||
"test2",
|
||||
"hellohello",
|
||||
"worldworldworld"
|
||||
|
||||
),
|
||||
|
||||
// Instruction using characters requiring multiple bytes in UTF-8 and
|
||||
// surrogate pairs in UTF-16, including an element ending with a surrogate
|
||||
// pair
|
||||
new TestCase(
|
||||
|
||||
"4.ab" + HIGH_SURROGATE + HIGH_SURROGATE + ","
|
||||
+ "6.a" + UTF8_MULTIBYTE + "b,"
|
||||
+ "5.12345,"
|
||||
+ "10.a" + UTF8_MULTIBYTE + UTF8_MULTIBYTE + "c;",
|
||||
|
||||
"ab" + HIGH_SURROGATE + HIGH_SURROGATE,
|
||||
"a" + UTF8_MULTIBYTE + "b",
|
||||
"12345",
|
||||
"a" + UTF8_MULTIBYTE + UTF8_MULTIBYTE + "c"
|
||||
|
||||
),
|
||||
|
||||
// Instruction with an element values ending with an incomplete surrogate
|
||||
// pair (high or low surrogate only)
|
||||
new TestCase(
|
||||
|
||||
"4.test,"
|
||||
+ "5.1234" + HIGH_SURROGATE + ","
|
||||
+ "5.4567" + LOW_SURROGATE + ";",
|
||||
|
||||
"test",
|
||||
"1234" + HIGH_SURROGATE,
|
||||
"4567" + LOW_SURROGATE
|
||||
|
||||
),
|
||||
|
||||
// Instruction with element values containing incomplete surrogate pairs
|
||||
new TestCase(
|
||||
|
||||
"5.te" + LOW_SURROGATE + "st,"
|
||||
+ "5.12" + HIGH_SURROGATE + "3" + LOW_SURROGATE + ","
|
||||
+ "6.5" + LOW_SURROGATE + LOW_SURROGATE + "4" + HIGH_SURROGATE + HIGH_SURROGATE + ","
|
||||
+ "10." + UTF8_MULTIBYTE + HIGH_SURROGATE + UTF8_MULTIBYTE + HIGH_SURROGATE + ";",
|
||||
|
||||
"te" + LOW_SURROGATE + "st",
|
||||
"12" + HIGH_SURROGATE + "3" + LOW_SURROGATE,
|
||||
"5" + LOW_SURROGATE + LOW_SURROGATE + "4" + HIGH_SURROGATE + HIGH_SURROGATE,
|
||||
UTF8_MULTIBYTE + HIGH_SURROGATE + UTF8_MULTIBYTE + HIGH_SURROGATE
|
||||
|
||||
)
|
||||
|
||||
));
|
||||
|
||||
/**
|
||||
* Verifies that instruction opcodes are represented correctly.
|
||||
*/
|
||||
@Test
|
||||
public void testGetOpcode() {
|
||||
for (TestCase testCase : TEST_CASES) {
|
||||
assertEquals(testCase.OPCODE, testCase.getOpcode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that instruction arguments are represented correctly.
|
||||
*/
|
||||
@Test
|
||||
public void testGetArgs() {
|
||||
for (TestCase testCase : TEST_CASES) {
|
||||
assertEquals(testCase.ARGS, testCase.getArgs());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that instructions are encoded correctly.
|
||||
*/
|
||||
@Test
|
||||
public void testToString() {
|
||||
for (TestCase testCase : TEST_CASES) {
|
||||
assertEquals(testCase.UNPARSED, testCase.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -20,6 +20,8 @@
|
||||
package org.apache.guacamole.protocol;
|
||||
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import static org.apache.guacamole.protocol.GuacamoleInstructionTest.TEST_CASES;
|
||||
import org.apache.guacamole.protocol.GuacamoleInstructionTest.TestCase;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -35,82 +37,46 @@ public class GuacamoleParserTest {
|
||||
private final GuacamoleParser parser = new GuacamoleParser();
|
||||
|
||||
/**
|
||||
* Test of append method, of class GuacamoleParser.
|
||||
*
|
||||
* @throws GuacamoleException If a parse error occurs while parsing the
|
||||
* known-good test string.
|
||||
* Verify that GuacamoleParser correctly parses each of the instruction
|
||||
* test cases included in the GuacamoleInstruction test.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If a parse error occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testParser() throws GuacamoleException {
|
||||
|
||||
// Test string
|
||||
char buffer[] = "1.a,2.bc,3.def,10.helloworld;4.test,5.test2;0.;3.foo;".toCharArray();
|
||||
// Build buffer containing all of the instruction test cases, one after
|
||||
// the other
|
||||
StringBuilder allTestCases = new StringBuilder();
|
||||
for (TestCase testCase : TEST_CASES)
|
||||
allTestCases.append(testCase.UNPARSED);
|
||||
|
||||
// Prepare buffer and offsets for feeding the data into the parser as
|
||||
// if received over the network
|
||||
char buffer[] = allTestCases.toString().toCharArray();
|
||||
int offset = 0;
|
||||
int length = buffer.length;
|
||||
|
||||
GuacamoleInstruction instruction;
|
||||
int parsed;
|
||||
// Verify that each of the expected instructions is received in order
|
||||
for (TestCase testCase : TEST_CASES) {
|
||||
|
||||
// Parse more data
|
||||
while (length > 0 && (parsed = parser.append(buffer, offset, length)) != 0) {
|
||||
offset += parsed;
|
||||
length -= parsed;
|
||||
}
|
||||
// Feed data into parser until parser refuses to receive more data
|
||||
int parsed;
|
||||
while (length > 0 && (parsed = parser.append(buffer, offset, length)) != 0) {
|
||||
offset += parsed;
|
||||
length -= parsed;
|
||||
}
|
||||
|
||||
// Validate first test instruction
|
||||
assertTrue(parser.hasNext());
|
||||
instruction = parser.next();
|
||||
assertNotNull(instruction);
|
||||
assertEquals(3, instruction.getArgs().size());
|
||||
assertEquals("a", instruction.getOpcode());
|
||||
assertEquals("bc", instruction.getArgs().get(0));
|
||||
assertEquals("def", instruction.getArgs().get(1));
|
||||
assertEquals("helloworld", instruction.getArgs().get(2));
|
||||
// An instruction should now be parsed and ready for retrieval
|
||||
assertTrue(parser.hasNext());
|
||||
|
||||
// Parse more data
|
||||
while (length > 0 && (parsed = parser.append(buffer, offset, length)) != 0) {
|
||||
offset += parsed;
|
||||
length -= parsed;
|
||||
}
|
||||
// Verify instruction contains expected opcode and args
|
||||
GuacamoleInstruction instruction = parser.next();
|
||||
assertNotNull(instruction);
|
||||
assertEquals(testCase.OPCODE, instruction.getOpcode());
|
||||
assertEquals(testCase.ARGS, instruction.getArgs());
|
||||
|
||||
// Validate second test instruction
|
||||
assertTrue(parser.hasNext());
|
||||
instruction = parser.next();
|
||||
assertNotNull(instruction);
|
||||
assertEquals(1, instruction.getArgs().size());
|
||||
assertEquals("test", instruction.getOpcode());
|
||||
assertEquals("test2", instruction.getArgs().get(0));
|
||||
|
||||
// Parse more data
|
||||
while (length > 0 && (parsed = parser.append(buffer, offset, length)) != 0) {
|
||||
offset += parsed;
|
||||
length -= parsed;
|
||||
}
|
||||
|
||||
// Validate third test instruction
|
||||
assertTrue(parser.hasNext());
|
||||
instruction = parser.next();
|
||||
assertNotNull(instruction);
|
||||
assertEquals(0, instruction.getArgs().size());
|
||||
assertEquals("", instruction.getOpcode());
|
||||
|
||||
// Parse more data
|
||||
while (length > 0 && (parsed = parser.append(buffer, offset, length)) != 0) {
|
||||
offset += parsed;
|
||||
length -= parsed;
|
||||
}
|
||||
|
||||
// Validate fourth test instruction
|
||||
assertTrue(parser.hasNext());
|
||||
instruction = parser.next();
|
||||
assertNotNull(instruction);
|
||||
assertEquals(0, instruction.getArgs().size());
|
||||
assertEquals("foo", instruction.getOpcode());
|
||||
|
||||
// Parse more data
|
||||
while (length > 0 && (parsed = parser.append(buffer, offset, length)) != 0) {
|
||||
offset += parsed;
|
||||
length -= parsed;
|
||||
}
|
||||
|
||||
// There should be no more instructions
|
||||
|
Reference in New Issue
Block a user