TLS and Graphics, what more?
This commit is contained in:
@@ -3,6 +3,7 @@ package org.lib3270j.datastream;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lib3270j.TerminalModel;
|
||||
import org.lib3270j.charset.EbcdicTranslator;
|
||||
import org.lib3270j.graphics.GraphicsMode;
|
||||
import org.lib3270j.screen.ScreenBuffer;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.lib3270j.protocol.DS3270Constants.*;
|
||||
@@ -14,11 +15,43 @@ public class QueryReplyBuilderTest {
|
||||
private final QueryReplyBuilder qrBuilder = new QueryReplyBuilder(screen);
|
||||
|
||||
@Test
|
||||
public void testBuildAllQueryReplies() {
|
||||
public void testBuildAllQueryRepliesDefaultNone() {
|
||||
assertEquals(GraphicsMode.NONE, qrBuilder.getGraphicsMode());
|
||||
byte[] replies = qrBuilder.buildAllQueryReplies(80, 43, 80 * 43);
|
||||
assertNotNull(replies);
|
||||
assertTrue(replies.length > 0);
|
||||
assertEquals((byte) AID_SF, replies[0]);
|
||||
|
||||
// In GraphicsMode.NONE, Vector Graphics QR 0xB0 must NOT be present
|
||||
boolean hasB0 = false;
|
||||
for (int i = 0; i < replies.length - 3; i++) {
|
||||
if ((replies[i] & 0xFF) == 0x81 && (replies[i + 1] & 0xFF) == QR_GRAPHICS) {
|
||||
hasB0 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertFalse(hasB0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildAllQueryRepliesWithVectorGraphics() {
|
||||
qrBuilder.setGraphicsMode(GraphicsMode.VECTOR_GRAPHICS);
|
||||
byte[] replies = qrBuilder.buildAllQueryReplies(80, 43, 80 * 43);
|
||||
assertNotNull(replies);
|
||||
|
||||
// Vector Graphics QR 0xB0 and 0xB4 must be present
|
||||
boolean hasB0 = false;
|
||||
boolean hasB4 = false;
|
||||
for (int i = 0; i < replies.length - 3; i++) {
|
||||
if ((replies[i] & 0xFF) == 0x81 && (replies[i + 1] & 0xFF) == QR_GRAPHICS) {
|
||||
hasB0 = true;
|
||||
}
|
||||
if ((replies[i] & 0xFF) == 0x81 && (replies[i + 1] & 0xFF) == QR_GCOLOR) {
|
||||
hasB4 = true;
|
||||
}
|
||||
}
|
||||
assertTrue(hasB0);
|
||||
assertTrue(hasB4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -52,4 +85,29 @@ public class QueryReplyBuilderTest {
|
||||
assertEquals(0x81, replies[3] & 0xFF);
|
||||
assertEquals(QR_NULL, replies[4] & 0xFF);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImplicitPartitionModel4() {
|
||||
byte[] requested = new byte[] { (byte) QR_IMP_PART };
|
||||
byte[] replies = qrBuilder.buildQueryReplies(requested, 80, 43, 80 * 43);
|
||||
|
||||
assertNotNull(replies);
|
||||
assertEquals((byte) AID_SF, replies[0]);
|
||||
int len = ((replies[1] & 0xFF) << 8) | (replies[2] & 0xFF);
|
||||
assertEquals(0x81, replies[3] & 0xFF); // SFID_QREPLY
|
||||
assertEquals(QR_IMP_PART, replies[4] & 0xFF); // 0xA6
|
||||
|
||||
// Payload starts at index 5: 22 bytes total
|
||||
// Default size = 80 x 24
|
||||
int defCols = ((replies[10] & 0xFF) << 8) | (replies[11] & 0xFF);
|
||||
int defRows = ((replies[12] & 0xFF) << 8) | (replies[13] & 0xFF);
|
||||
assertEquals(80, defCols);
|
||||
assertEquals(24, defRows);
|
||||
|
||||
// Alt size = 80 x 43
|
||||
int altCols = ((replies[14] & 0xFF) << 8) | (replies[15] & 0xFF);
|
||||
int altRows = ((replies[16] & 0xFF) << 8) | (replies[17] & 0xFF);
|
||||
assertEquals(80, altCols);
|
||||
assertEquals(43, altRows);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
package org.lib3270j.graphics;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class GocaDecoderTest {
|
||||
|
||||
@Test
|
||||
public void testBasicLineAndColorOrders() {
|
||||
GraphicsPlane plane = new GraphicsPlane(400, 300);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
assertFalse(plane.hasContent());
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// Set Color to Red (GOCA Color 2) - 2 bytes: order, color
|
||||
out.write(GocaConstants.G_GSCOL);
|
||||
out.write(0x02); // Red
|
||||
|
||||
// Line from (1000, 1000) to (2000, 2000) - long order: order, len, x1, y1, x2, y2
|
||||
out.write(GocaConstants.G_GLINE);
|
||||
out.write(0x08); // 8 bytes: (x1, y1, x2, y2)
|
||||
out.write((1000 >> 8) & 0xFF); out.write(1000 & 0xFF);
|
||||
out.write((1000 >> 8) & 0xFF); out.write(1000 & 0xFF);
|
||||
out.write((2000 >> 8) & 0xFF); out.write(2000 & 0xFF);
|
||||
out.write((2000 >> 8) & 0xFF); out.write(2000 & 0xFF);
|
||||
|
||||
byte[] stream = out.toByteArray();
|
||||
decoder.decodeStream(stream, 0, stream.length);
|
||||
|
||||
assertTrue(plane.hasContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAreaAndPatternFill() {
|
||||
GraphicsPlane plane = new GraphicsPlane(400, 300);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// Set Pattern to Solid - 2 bytes: order, pattern
|
||||
out.write(GocaConstants.G_GSPT);
|
||||
out.write(GocaConstants.PT_SOLID);
|
||||
|
||||
// Begin Area - 2 bytes: order, flags
|
||||
out.write(GocaConstants.G_GBAR);
|
||||
out.write(0x00);
|
||||
|
||||
// Polyline forming a triangle: (500, 500) -> (1500, 500) -> (1000, 1500) -> (500, 500)
|
||||
out.write(GocaConstants.G_GLINE);
|
||||
out.write(0x10); // 4 points * 4 bytes = 16 bytes
|
||||
out.write((500 >> 8) & 0xFF); out.write(500 & 0xFF);
|
||||
out.write((500 >> 8) & 0xFF); out.write(500 & 0xFF);
|
||||
|
||||
out.write((1500 >> 8) & 0xFF); out.write(1500 & 0xFF);
|
||||
out.write((500 >> 8) & 0xFF); out.write(500 & 0xFF);
|
||||
|
||||
out.write((1000 >> 8) & 0xFF); out.write(1000 & 0xFF);
|
||||
out.write((1500 >> 8) & 0xFF); out.write(1500 & 0xFF);
|
||||
|
||||
out.write((500 >> 8) & 0xFF); out.write(500 & 0xFF);
|
||||
out.write((500 >> 8) & 0xFF); out.write(500 & 0xFF);
|
||||
|
||||
// End Area - 1 byte
|
||||
out.write(GocaConstants.G_GEAR);
|
||||
|
||||
byte[] stream = out.toByteArray();
|
||||
decoder.decodeStream(stream, 0, stream.length);
|
||||
|
||||
assertTrue(plane.hasContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarkerAndVectorText() {
|
||||
GraphicsPlane plane = new GraphicsPlane(400, 300);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// Set Marker Type to Circle - 2 bytes: order, type
|
||||
out.write(GocaConstants.G_GSMT);
|
||||
out.write(GocaConstants.MK_CIRCLE);
|
||||
|
||||
// Draw Marker at (2000, 2000)
|
||||
out.write(GocaConstants.G_GMRK);
|
||||
out.write(0x04);
|
||||
out.write((2000 >> 8) & 0xFF); out.write(2000 & 0xFF);
|
||||
out.write((2000 >> 8) & 0xFF); out.write(2000 & 0xFF);
|
||||
|
||||
// Draw Vector Stroked Character String: "IBM" (EBCDIC: 0xC9, 0xC2, 0xD4)
|
||||
out.write(GocaConstants.G_GCHST);
|
||||
out.write(0x07); // 4 bytes pos + 3 bytes chars
|
||||
out.write((1000 >> 8) & 0xFF); out.write(1000 & 0xFF);
|
||||
out.write((1000 >> 8) & 0xFF); out.write(1000 & 0xFF);
|
||||
out.write(0xC9); out.write(0xC2); out.write(0xD4);
|
||||
|
||||
byte[] stream = out.toByteArray();
|
||||
decoder.decodeStream(stream, 0, stream.length);
|
||||
|
||||
assertTrue(plane.hasContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureOrdersAndErase() {
|
||||
GraphicsPlane plane = new GraphicsPlane(400, 300);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
// Draw something first
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(GocaConstants.G_GLINE);
|
||||
out.write(0x08);
|
||||
out.write(0x00); out.write(0x00);
|
||||
out.write(0x00); out.write(0x00);
|
||||
out.write(0x00); out.write(0x64);
|
||||
out.write(0x00); out.write(0x64);
|
||||
byte[] drawStream = out.toByteArray();
|
||||
decoder.decodeStream(drawStream, 0, drawStream.length);
|
||||
assertTrue(plane.hasContent());
|
||||
|
||||
// Process procedure order 0x0A (Erase presentation space)
|
||||
byte[] procOrders = new byte[] { (byte) GocaConstants.P_ERASE };
|
||||
decoder.processProcedureOrders(procOrders, 0, procOrders.length);
|
||||
assertFalse(plane.hasContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSegmentAndRelativeLineOrders() {
|
||||
GraphicsPlane plane = new GraphicsPlane(720, 688);
|
||||
plane.setScreenDimensions(80, 43);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// 0x70: Begin Segment (14 bytes total)
|
||||
out.write(GocaConstants.G_BEGSEGM);
|
||||
out.write(0x0C);
|
||||
out.write(0x00); out.write(0x00); out.write(0x00); out.write(0x01); // Seg ID 1
|
||||
out.write(0x74); out.write(0x70);
|
||||
out.write(0x00); out.write(0x1E); out.write(0x00); out.write(0x00); out.write(0x00); out.write(0x00);
|
||||
|
||||
// 0x3E: End Prologue
|
||||
out.write(GocaConstants.G_ENDPROLOGUE);
|
||||
out.write(0x00);
|
||||
|
||||
// 0x0A: Color (7 = White)
|
||||
out.write(GocaConstants.G_GSCOL);
|
||||
out.write(0x07);
|
||||
|
||||
// 0xE1: Relative Line (Absolute Start (300, 200), deltas: (+10, -5), (-10, +5))
|
||||
out.write(GocaConstants.G_GRLINE);
|
||||
out.write(0x08); // 4 bytes start coord + 4 bytes (2 deltas) = 8 bytes
|
||||
out.write(0x01); out.write(0x2C); // Start X = 300
|
||||
out.write(0x00); out.write(0xC8); // Start Y = 200
|
||||
out.write(0x0A); out.write(0xFB); // dx = +10, dy = -5
|
||||
out.write(0xF6); out.write(0x05); // dx = -10, dy = +5
|
||||
|
||||
// 0x71: End Segment
|
||||
out.write(GocaConstants.G_ENDSEGM);
|
||||
out.write(0x00);
|
||||
|
||||
byte[] stream = out.toByteArray();
|
||||
decoder.decodeStream(stream, 0, stream.length);
|
||||
assertTrue(plane.hasContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartialOrderBufferingAcrossStreams() {
|
||||
GraphicsPlane plane = new GraphicsPlane(400, 300);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
// First packet sends G_GLINE order code and half of its coordinates
|
||||
ByteArrayOutputStream chunk1 = new ByteArrayOutputStream();
|
||||
chunk1.write(GocaConstants.G_GLINE);
|
||||
chunk1.write(0x08); // 8 bytes: 2 points
|
||||
chunk1.write(0x00); chunk1.write(0x64); // x1 = 100
|
||||
chunk1.write(0x00); chunk1.write(0x64); // y1 = 100
|
||||
|
||||
byte[] b1 = chunk1.toByteArray();
|
||||
decoder.decodeStream(b1, 0, b1.length);
|
||||
// Order is not complete yet, so no line drawn yet
|
||||
assertFalse(plane.hasContent());
|
||||
|
||||
// Second packet sends the rest of the order: x2 = 200, y2 = 200
|
||||
ByteArrayOutputStream chunk2 = new ByteArrayOutputStream();
|
||||
chunk2.write(0x00); chunk2.write(0xC8); // x2 = 200
|
||||
chunk2.write(0x00); chunk2.write(0xC8); // y2 = 200
|
||||
|
||||
byte[] b2 = chunk2.toByteArray();
|
||||
decoder.decodeStream(b2, 0, b2.length);
|
||||
// Now the combined order executes!
|
||||
assertTrue(plane.hasContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCurrentPositionAndRelativeLine() {
|
||||
GraphicsPlane plane = new GraphicsPlane(400, 300);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// 0x21: Set Current Position to (50, 50)
|
||||
out.write(GocaConstants.G_GSCP);
|
||||
out.write(0x04); // len = 4
|
||||
out.write(0x00); out.write(0x32); // x = 50
|
||||
out.write(0x00); out.write(0x32); // y = 50
|
||||
|
||||
// 0xA1: Relative Line from Current Position: (+10, +20), (-5, -10)
|
||||
out.write(GocaConstants.G_GCRLIN);
|
||||
out.write(0x04); // len = 4 (2 steps)
|
||||
out.write(0x0A); out.write(0x14); // dx = +10, dy = +20
|
||||
out.write(0xFB); out.write(0xF6); // dx = -5, dy = -10
|
||||
|
||||
byte[] stream = out.toByteArray();
|
||||
decoder.decodeStream(stream, 0, stream.length);
|
||||
|
||||
assertTrue(plane.hasContent());
|
||||
assertEquals(55, decoder.getCurX());
|
||||
assertEquals(60, decoder.getCurY());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3179GCoordinateMapping() {
|
||||
GraphicsPlane plane = new GraphicsPlane(720, 688);
|
||||
plane.setScreenDimensions(80, 43);
|
||||
|
||||
// Screen center (0, 0) should map to canvas center (360, 343)
|
||||
assertEquals(360, plane.mapX(0));
|
||||
assertEquals(343, plane.mapY(0));
|
||||
|
||||
// Left edge (-360) should map to 0
|
||||
assertEquals(0, plane.mapX(-360));
|
||||
// Right edge (+359) should map to 719
|
||||
assertEquals(719, plane.mapX(359));
|
||||
|
||||
// Top edge (+343) should map to 0
|
||||
assertEquals(0, plane.mapY(343));
|
||||
// Bottom edge (-344) should map to 687
|
||||
assertEquals(687, plane.mapY(-344));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.lib3270j.graphics;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lib3270j.ConnectionConfig;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class GraphicsModeTest {
|
||||
|
||||
@Test
|
||||
public void testDefaultsAndParsing() {
|
||||
assertEquals(GraphicsMode.NONE, GraphicsMode.fromString(null));
|
||||
assertEquals(GraphicsMode.NONE, GraphicsMode.fromString(""));
|
||||
assertEquals(GraphicsMode.NONE, GraphicsMode.fromString("NONE"));
|
||||
assertEquals(GraphicsMode.NONE, GraphicsMode.fromString("off"));
|
||||
assertEquals(GraphicsMode.NONE, GraphicsMode.fromString("false"));
|
||||
|
||||
assertEquals(GraphicsMode.PROGRAMMED_SYMBOLS, GraphicsMode.fromString("ps"));
|
||||
assertEquals(GraphicsMode.PROGRAMMED_SYMBOLS, GraphicsMode.fromString("programmed_symbols"));
|
||||
assertEquals(GraphicsMode.PROGRAMMED_SYMBOLS, GraphicsMode.fromString("apl"));
|
||||
|
||||
assertEquals(GraphicsMode.VECTOR_GRAPHICS, GraphicsMode.fromString("vector"));
|
||||
assertEquals(GraphicsMode.VECTOR_GRAPHICS, GraphicsMode.fromString("goca"));
|
||||
assertEquals(GraphicsMode.VECTOR_GRAPHICS, GraphicsMode.fromString("vector_graphics"));
|
||||
|
||||
assertEquals(GraphicsMode.BOTH, GraphicsMode.fromString("both"));
|
||||
assertEquals(GraphicsMode.BOTH, GraphicsMode.fromString("all"));
|
||||
assertEquals(GraphicsMode.BOTH, GraphicsMode.fromString("true"));
|
||||
assertEquals(GraphicsMode.BOTH, GraphicsMode.fromString("on"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlags() {
|
||||
assertFalse(GraphicsMode.NONE.isProgrammedSymbolsEnabled());
|
||||
assertFalse(GraphicsMode.NONE.isVectorGraphicsEnabled());
|
||||
|
||||
assertTrue(GraphicsMode.PROGRAMMED_SYMBOLS.isProgrammedSymbolsEnabled());
|
||||
assertFalse(GraphicsMode.PROGRAMMED_SYMBOLS.isVectorGraphicsEnabled());
|
||||
|
||||
assertFalse(GraphicsMode.VECTOR_GRAPHICS.isProgrammedSymbolsEnabled());
|
||||
assertTrue(GraphicsMode.VECTOR_GRAPHICS.isVectorGraphicsEnabled());
|
||||
|
||||
assertTrue(GraphicsMode.BOTH.isProgrammedSymbolsEnabled());
|
||||
assertTrue(GraphicsMode.BOTH.isVectorGraphicsEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionConfigDefault() {
|
||||
ConnectionConfig config = new ConnectionConfig();
|
||||
assertEquals(GraphicsMode.NONE, config.getGraphicsMode());
|
||||
|
||||
config.setGraphicsMode(GraphicsMode.BOTH);
|
||||
assertEquals(GraphicsMode.BOTH, config.getGraphicsMode());
|
||||
|
||||
config.setGraphicsMode(null);
|
||||
assertEquals(GraphicsMode.NONE, config.getGraphicsMode());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package org.lib3270j.graphics;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ProgramSymbolManagerTest {
|
||||
|
||||
@Test
|
||||
public void testSetAllocationAndLookup() {
|
||||
ProgramSymbolManager manager = new ProgramSymbolManager();
|
||||
// Loadable set can be queried after loadps or clearAll
|
||||
assertNull(manager.getSymbolSet(0x40));
|
||||
assertNull(manager.getSymbol(0x40, 0x41));
|
||||
|
||||
manager.clearAll();
|
||||
assertNull(manager.getSymbolSet(0x40));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSinglePlaneLoadPsFormat1() {
|
||||
ProgramSymbolManager manager = new ProgramSymbolManager();
|
||||
|
||||
// Build Format 1 Load PS payload for LCID 0x40, code point 0x41 ('A')
|
||||
// Format 1 header:
|
||||
// byte 0: flags (0x01: format 1, single plane)
|
||||
// byte 1: LCID (0x40)
|
||||
// byte 2: Start code point (0x41)
|
||||
// byte 3: RWS (0x02: loadable slot 2)
|
||||
// followed by 18 bytes per symbol for 9x16 cell:
|
||||
// Byte 0-1: Col 0 for rows 0..15 (0x80 = bit for row 0 col 0)
|
||||
// Bytes 2-17: Cols 1..8 for rows 0..15 (0xFF = bits for row 0 cols 1..8)
|
||||
byte[] payload = new byte[4 + 18];
|
||||
payload[0] = 0x01; // Format 1
|
||||
payload[1] = 0x40; // LCID 0x40
|
||||
payload[2] = 0x41; // Code point 0x41
|
||||
payload[3] = 0x02; // RWS 2
|
||||
|
||||
payload[4] = (byte) 0x80; // Row 0 Col 0 bit
|
||||
payload[5] = (byte) 0x00; // Rows 8..15 Col 0
|
||||
for (int r = 0; r < 16; r++) {
|
||||
payload[6 + r] = (byte) 0xFF; // Cols 1..8 on all rows
|
||||
}
|
||||
|
||||
manager.loadps(payload);
|
||||
|
||||
ProgramSymbolSet set = manager.getSymbolSet(0x40);
|
||||
assertNotNull(set);
|
||||
assertEquals(0x40, set.getLcid());
|
||||
assertFalse(set.isTriplePlane());
|
||||
|
||||
ProgramSymbolSet.SymbolSlot slot = manager.getSymbol(0x40, 0x41);
|
||||
assertNotNull(slot);
|
||||
assertEquals(9, slot.getWidth());
|
||||
assertEquals(16, slot.getHeight());
|
||||
assertFalse(slot.isTriplePlane());
|
||||
|
||||
// Verify pixel data (Row 0 Col 0 is 1)
|
||||
byte[] pixels = slot.getPixelData();
|
||||
assertNotNull(pixels);
|
||||
assertEquals(1, pixels[0]); // Row 0 Col 0 is 1
|
||||
|
||||
// Test rendering into BufferedImage
|
||||
BufferedImage canvas = new BufferedImage(80, 24, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2 = canvas.createGraphics();
|
||||
boolean drawn = manager.drawSymbol(g2, 0x40, 0x41, 0, 0, 10, 20, Color.GREEN, Color.BLACK);
|
||||
g2.dispose();
|
||||
assertTrue(drawn);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTriplePlaneMultiColorComposite() {
|
||||
ProgramSymbolManager manager = new ProgramSymbolManager();
|
||||
|
||||
// Build Format 1 Load PS payload for LCID 0x42, triple plane
|
||||
// flags = 0x01 (Format 1)
|
||||
// RWS = 4 (Triple Plane)
|
||||
byte[] payload = new byte[4 + 18];
|
||||
payload[0] = 0x01; // Format 1
|
||||
payload[1] = 0x42; // LCID 0x42
|
||||
payload[2] = 0x45; // Code point 0x45
|
||||
payload[3] = 0x04; // RWS 4 (Triple Plane)
|
||||
|
||||
// Set pixel at row 0 col 0
|
||||
payload[4] = (byte) 0x80; // Row 0 Col 0
|
||||
payload[5] = (byte) 0x00;
|
||||
for (int r = 0; r < 16; r++) {
|
||||
payload[6 + r] = (byte) 0x00;
|
||||
}
|
||||
|
||||
manager.loadps(payload);
|
||||
|
||||
ProgramSymbolSet set = manager.getSymbolSet(0x42);
|
||||
assertNotNull(set);
|
||||
assertTrue(set.isTriplePlane());
|
||||
|
||||
ProgramSymbolSet.SymbolSlot slot = manager.getSymbol(0x42, 0x45);
|
||||
assertNotNull(slot);
|
||||
assertTrue(slot.isTriplePlane());
|
||||
|
||||
// When loaded with colorPlane=0 (default), all 3 planes are set (val 7 = white composite)
|
||||
byte[] pixels = slot.getPixelData();
|
||||
assertEquals(7, pixels[0] & 0xFF);
|
||||
|
||||
// Render image
|
||||
BufferedImage img = slot.getImage(Color.WHITE, Color.BLACK);
|
||||
assertNotNull(img);
|
||||
|
||||
// Pixel (0,0) should be white composite (Red=255, Green=255, Blue=255)
|
||||
int rgb = img.getRGB(0, 0);
|
||||
Color pixelColor = new Color(rgb, true);
|
||||
assertEquals(255, pixelColor.getRed());
|
||||
assertEquals(255, pixelColor.getGreen());
|
||||
assertEquals(255, pixelColor.getBlue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormat3Bitstream() {
|
||||
ProgramSymbolManager manager = new ProgramSymbolManager();
|
||||
|
||||
// Format 3 payload
|
||||
// byte 0: 0x03 (Format 3)
|
||||
// byte 1: LCID (0x44)
|
||||
// byte 2: code point (0x43)
|
||||
// byte 3: RWS (2)
|
||||
// followed by (9 * 16 + 7) / 8 = 18 bytes
|
||||
byte[] payload = new byte[4 + 18];
|
||||
payload[0] = 0x03; // Format 3
|
||||
payload[1] = 0x44; // LCID 0x44
|
||||
payload[2] = 0x43; // Code point 0x43
|
||||
payload[3] = 0x02; // RWS 2
|
||||
payload[4] = (byte) 0x80; // First pixel is set
|
||||
|
||||
manager.loadps(payload);
|
||||
|
||||
ProgramSymbolSet set = manager.getSymbolSet(0x44);
|
||||
assertNotNull(set);
|
||||
ProgramSymbolSet.SymbolSlot slot = manager.getSymbol(0x44, 0x43);
|
||||
assertNotNull(slot);
|
||||
assertEquals(1, slot.getPixelData()[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.lib3270j.tls;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lib3270j.ConnectionConfig;
|
||||
import org.lib3270j.TerminalModel;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TlsConfigTest {
|
||||
|
||||
@Test
|
||||
public void testConnectionConfigDefaults() {
|
||||
ConnectionConfig config = new ConnectionConfig("localhost", 23);
|
||||
assertFalse(config.isUseTls());
|
||||
assertTrue(config.isTlsVerifyCert());
|
||||
assertEquals("TLS", config.getSslProtocol());
|
||||
assertNull(config.getCertificateVerifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseHostStringTlsPrefixes() {
|
||||
// L: prefix
|
||||
ConnectionConfig c1 = ConnectionConfig.parseHostString("L:mainframe.example.com", 0, TerminalModel.IBM_3279_4);
|
||||
assertTrue(c1.isUseTls());
|
||||
assertEquals("mainframe.example.com", c1.getHost());
|
||||
assertEquals(992, c1.getPort());
|
||||
|
||||
// ssl: prefix with explicit port
|
||||
ConnectionConfig c2 = ConnectionConfig.parseHostString("ssl:zos.local:2323", 0, TerminalModel.IBM_3279_2);
|
||||
assertTrue(c2.isUseTls());
|
||||
assertEquals("zos.local", c2.getHost());
|
||||
assertEquals(2323, c2.getPort());
|
||||
|
||||
// y: prefix
|
||||
ConnectionConfig c3 = ConnectionConfig.parseHostString("y:vm370.net:992", 23, TerminalModel.IBM_3279_4);
|
||||
assertTrue(c3.isUseTls());
|
||||
assertEquals("vm370.net", c3.getHost());
|
||||
assertEquals(992, c3.getPort());
|
||||
|
||||
// Plain host
|
||||
ConnectionConfig c4 = ConnectionConfig.parseHostString("plain.host.com", 23, TerminalModel.IBM_3279_4);
|
||||
assertFalse(c4.isUseTls());
|
||||
assertEquals("plain.host.com", c4.getHost());
|
||||
assertEquals(23, c4.getPort());
|
||||
|
||||
// IPv6 host with brackets
|
||||
ConnectionConfig c5 = ConnectionConfig.parseHostString("L:[2001:db8::1]:992", 0, TerminalModel.IBM_3279_4);
|
||||
assertTrue(c5.isUseTls());
|
||||
assertEquals("2001:db8::1", c5.getHost());
|
||||
assertEquals(992, c5.getPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTlsTrustManagerBypass() {
|
||||
ConnectionConfig config = new ConnectionConfig("untrusted.host", 992);
|
||||
config.setUseTls(true);
|
||||
config.setTlsVerifyCert(false);
|
||||
|
||||
TlsTrustManager trustManager = new TlsTrustManager(config);
|
||||
// With tlsVerifyCert=false, checkServerTrusted must not throw even with null/empty chain
|
||||
assertDoesNotThrow(() -> trustManager.checkServerTrusted(new X509Certificate[0], "RSA"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTlsTrustManagerVerifierCallback() {
|
||||
ConnectionConfig config = new ConnectionConfig("selfsigned.host", 992);
|
||||
config.setUseTls(true);
|
||||
config.setTlsVerifyCert(true);
|
||||
|
||||
AtomicBoolean verifierInvoked = new AtomicBoolean(false);
|
||||
config.setCertificateVerifier((chain, authType, exception) -> {
|
||||
verifierInvoked.set(true);
|
||||
return true; // Accept certificate
|
||||
});
|
||||
|
||||
TlsTrustManager trustManager = new TlsTrustManager(config);
|
||||
// Standard verification will fail on empty cert chain, triggering our callback
|
||||
assertDoesNotThrow(() -> trustManager.checkServerTrusted(new X509Certificate[0], "RSA"));
|
||||
assertTrue(verifierInvoked.get(), "Expected verifier callback to be invoked");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTlsTrustManagerVerifierRejection() {
|
||||
ConnectionConfig config = new ConnectionConfig("badcert.host", 992);
|
||||
config.setUseTls(true);
|
||||
config.setTlsVerifyCert(true);
|
||||
|
||||
config.setCertificateVerifier((chain, authType, exception) -> false); // Reject certificate
|
||||
|
||||
TlsTrustManager trustManager = new TlsTrustManager(config);
|
||||
assertThrows(CertificateException.class, () -> trustManager.checkServerTrusted(new X509Certificate[0], "RSA"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSSLContext() throws Exception {
|
||||
ConnectionConfig config = new ConnectionConfig("secure.host", 992);
|
||||
config.setUseTls(true);
|
||||
|
||||
SSLContext context = TlsTrustManager.createSSLContext(config);
|
||||
assertNotNull(context);
|
||||
assertNotNull(context.getSocketFactory());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user