1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// SPDX-License-Identifier: LGPL-2.1
//! Connection management and basic API tests
// Connection type is accessed via common::try_connect() helpers
mod common;
#[test]
fn test_connection_open_default() {
// Test basic connection with default settings
match common::try_connect() {
Ok(conn) => {
// Connection succeeded - verify basics
let fd = conn.file_descriptor();
assert!(fd >= 0, "File descriptor should be valid");
println!("Connection opened successfully, fd: {fd}");
}
Err(e) => {
// Connection failed - acceptable if no daemon running
println!("Connection failed (expected if no brltty daemon): {e}");
// Don't fail the test - this is environment dependent
}
}
}
#[test]
fn test_connection_with_localhost_settings() {
let settings = common::localhost_settings();
match common::try_connect_with_settings(&settings) {
Ok(conn) => {
let fd = conn.file_descriptor();
assert!(fd >= 0, "File descriptor should be valid");
println!("Localhost connection opened successfully, fd: {fd}");
}
Err(e) => {
println!("Localhost connection failed: {e}");
// Environment dependent - don't fail test
}
}
}
#[test]
fn test_connection_with_ipv4_settings() {
let settings = common::ipv4_settings();
match common::try_connect_with_settings(&settings) {
Ok(conn) => {
let fd = conn.file_descriptor();
assert!(fd >= 0, "File descriptor should be valid");
println!("IPv4 connection opened successfully, fd: {fd}");
}
Err(e) => {
println!("IPv4 connection failed: {e}");
}
}
}
#[test]
fn test_connection_cycling() {
// Test sequential connection establishment and cleanup
// While BrlAPI theoretically supports multiple simultaneous connections via handles,
// empirical testing shows connection establishment may be serialized by the daemon
// Use fewer connections in CI environments to avoid resource exhaustion
let connection_count = std::env::var("BRLAPI_TEST_CONNECTIONS")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(if std::env::var("CI").is_ok() { 2 } else { 3 });
println!(
"Testing {} sequential BrlAPI connections...",
connection_count
);
let mut successful_connections = 0;
for i in 0..connection_count {
match common::try_connect() {
Ok(conn) => {
let fd = conn.file_descriptor();
println!("Connection {i} opened, fd: {fd}");
successful_connections += 1;
// Test basic operations
if let Ok((width, height)) = conn.display_size() {
println!("Connection {i}: Display size {width}x{height}");
}
if let Ok(driver) = conn.display_driver() {
println!("Connection {i}: Driver '{driver}'");
}
// Connection is automatically closed when conn goes out of scope
drop(conn);
println!("Connection {i} closed");
}
Err(e) => {
println!("Connection {i} failed: {e}");
// Continue trying - some failures are expected if no daemon is running
}
}
}
// Test passes if we got at least one connection or all failed gracefully
println!("Successfully cycled through {successful_connections} connections");
}
#[test]
fn test_connection_drop_cleanup() {
// Test that connections are properly cleaned up when dropped
let conn_result = common::try_connect();
if let Ok(conn) = conn_result {
let fd = conn.file_descriptor();
println!("Connection opened with fd: {fd}");
// Drop explicitly to test cleanup
drop(conn);
println!("Connection dropped - cleanup should have occurred");
// Note: We can't easily test that cleanup actually worked
// without inspecting BrlAPI internal state, but the test
// verifies the drop doesn't panic
}
}
#[test]
fn test_connection_file_descriptor_validity() {
// Test that file descriptors returned are valid
if let Ok(conn) = common::try_connect() {
let fd = conn.file_descriptor();
// File descriptor should be non-negative
assert!(fd >= 0, "File descriptor should be non-negative, got {fd}");
// File descriptor should not be one of the standard descriptors
// (unless explicitly redirected, but that would be unusual for BrlAPI)
if fd <= 2 {
println!("Warning: File descriptor {fd} is a standard descriptor");
}
// Test that the same connection returns the same FD
let fd2 = conn.file_descriptor();
assert_eq!(
fd, fd2,
"Connection should return consistent file descriptor"
);
println!("Connection file descriptor: {fd}");
} else {
println!("No connection available for file descriptor testing");
}
}
#[test]
fn test_connection_methods_without_connection() {
// Test that connection methods handle disconnected state gracefully
let conn_result = common::try_connect();
match conn_result {
Ok(conn) => {
// Test driver information retrieval
let driver_result = conn.display_driver();
let driver_name = if let Some(name) =
common::assert_reasonable_result(driver_result, "Driver name query")
{
assert!(!name.is_empty(), "Driver name should not be empty");
assert!(name.len() <= brlapi_sys::BRLAPI_MAXNAMELENGTH as usize);
Some(name)
} else {
None
};
// Test model identifier retrieval
let model_result = conn.display_model();
if let Some(model) =
common::assert_reasonable_result(model_result, "Model identifier query")
{
// Some drivers (like NoBraille) may return empty model identifiers
// This is valid behavior, so we only check length constraints
assert!(model.len() <= brlapi_sys::BRLAPI_MAXNAMELENGTH as usize);
if !model.is_empty() {
println!("Model identifier: {model}");
} else {
println!("Model identifier: (empty - valid for some drivers like NoBraille)");
}
}
// Test display size retrieval
let display_result = conn.display_size();
if let Some((width, height)) =
common::assert_reasonable_result(display_result, "Display size query")
{
// Skip size assertions for NoBraille driver which typically has 0x0 dimensions
if let Some(ref name) = driver_name {
if name == "NoBraille" {
println!(
"Skipping size assertions for NoBraille driver (width={width}, height={height})"
);
} else {
assert!(
width > 0 && width <= 1000,
"Width should be reasonable for {name}"
);
assert!(
height > 0 && height <= 100,
"Height should be reasonable for {name}"
);
}
} else {
// If we don't know the driver name, be more lenient
assert!(width <= 1000, "Width should be within reasonable bounds");
assert!(height <= 100, "Height should be within reasonable bounds");
}
}
}
Err(e) => {
println!("Connection failed, testing with failed connection: {e}");
// Test passes - we're testing graceful handling of no connection
}
}
}