1package cef
2
3import (
4 "testing"
5
6 purecef "github.com/bnema/purego-cef/cef"
7 cefmocks "github.com/bnema/purego-cef/cef/mocks"
8 "github.com/stretchr/testify/assert"
9 "github.com/stretchr/testify/require"
10)
11
12type stubCEFValue struct{}
13
14func (stubCEFValue) IsValid() bool { return true }
15func (stubCEFValue) IsOwned() bool { return false }
16func (stubCEFValue) IsReadOnly() bool { return true }
17func (stubCEFValue) IsSame(purecef.Value) bool { return false }
18func (stubCEFValue) IsEqual(purecef.Value) bool { return false }
19func (stubCEFValue) Copy() purecef.Value { return stubCEFValue{} }
20func (stubCEFValue) GetType() purecef.ValueType { return 0 }
21func (stubCEFValue) GetBool() int32 { return 0 }
22func (stubCEFValue) GetInt() int32 { return 0 }
23func (stubCEFValue) GetDouble() float64 { return 0 }
24func (stubCEFValue) GetString() string { return "" }
25func (stubCEFValue) GetBinary() purecef.BinaryValue { return nil }
26func (stubCEFValue) GetDictionary() purecef.DictionaryValue { return nil }
27func (stubCEFValue) GetList() purecef.ListValue { return nil }
28func (stubCEFValue) SetNull() int32 { return 0 }
29func (stubCEFValue) SetBool(int32) int32 { return 0 }
30func (stubCEFValue) SetInt(int32) int32 { return 0 }
31func (stubCEFValue) SetDouble(float64) int32 { return 0 }
32func (stubCEFValue) SetString(string) int32 { return 0 }
33func (stubCEFValue) SetBinary(purecef.BinaryValue) int32 { return 0 }
34func (stubCEFValue) SetDictionary(purecef.DictionaryValue) int32 { return 0 }
35func (stubCEFValue) SetList(purecef.ListValue) int32 { return 0 }
36
37func TestRenderHandlerExposesAccessibilityAtWrapTime(t *testing.T) {
38 h := &dumberRenderHandler{a11y: newAccessibilityHandler(nil)}
39 if h.GetAccessibilityHandler() == nil {
40 t.Fatal("CEF would omit the accessibility override at wrap time")
41 }
42}
43
44func TestRenderHandlerExposesAccessibilityWhenMainExists(t *testing.T) {
45 // Must fail open (nil) when a11y was not installed, even if main exists —
46 // never fall back to h.main.GetAccessibilityHandler().
47 mainHandler := cefmocks.NewMockRenderHandler(t)
48 h := &dumberRenderHandler{main: mainHandler, a11y: nil}
49 assert.Nil(t, h.GetAccessibilityHandler())
50 mainHandler.AssertNotCalled(t, "GetAccessibilityHandler")
51
52 h.a11y = newAccessibilityHandler(nil)
53 require.NotNil(t, h.GetAccessibilityHandler())
54 mainHandler.AssertNotCalled(t, "GetAccessibilityHandler")
55}
56
57func TestNewDumberRenderHandlerInstallsNonNilAccessibilityHandler(t *testing.T) {
58 require.Nil(t, newDumberRenderHandler(nil))
59
60 wv := &WebView{viewBridge: &Cef2gtkAdapter{}}
61 rh := newDumberRenderHandler(wv)
62 require.NotNil(t, rh)
63 require.NotNil(t, rh.GetAccessibilityHandler())
64
65 handler, ok := rh.GetAccessibilityHandler().(*accessibilityHandler)
66 require.True(t, ok)
67 assert.Nil(t, handler.sink)
68}
69
70func TestAccessibilityHandler_NilSinkSkipsWriteJSON(t *testing.T) {
71 calls := 0
72 handler, ok := newAccessibilityHandler(nil).(*accessibilityHandler)
73 require.True(t, ok)
74 handler.writeJSON = func(purecef.Value, purecef.JsonWriterOptions) string {
75 calls++
76 return `{"unexpected":true}`
77 }
78
79 handler.OnAccessibilityTreeChange(stubCEFValue{})
80 handler.OnAccessibilityLocationChange(stubCEFValue{})
81 assert.Equal(t, 0, calls)
82}
83
84func TestAccessibilityHandler_NilValueIgnored(t *testing.T) {
85 calls := 0
86 var got []accessibilityPayload
87 handler, ok := newAccessibilityHandler(func(p accessibilityPayload) bool {
88 got = append(got, p)
89 return true
90 }).(*accessibilityHandler)
91 require.True(t, ok)
92 handler.writeJSON = func(purecef.Value, purecef.JsonWriterOptions) string {
93 calls++
94 return `{}`
95 }
96
97 handler.OnAccessibilityTreeChange(nil)
98 handler.OnAccessibilityLocationChange(nil)
99 assert.Equal(t, 0, calls)
100 assert.Empty(t, got)
101}
102
103func TestAccessibilityHandler_TreeAndLocationWriteJSONOnce(t *testing.T) {
104 var writeCalls []string
105 var got []accessibilityPayload
106 handler, ok := newAccessibilityHandler(func(p accessibilityPayload) bool {
107 got = append(got, p)
108 return true
109 }).(*accessibilityHandler)
110 require.True(t, ok)
111 handler.writeJSON = func(value purecef.Value, options purecef.JsonWriterOptions) string {
112 require.Equal(t, purecef.JsonWriterOptionsJsonWriterDefault, options)
113 require.NotNil(t, value)
114 writeCalls = append(writeCalls, "write")
115 return `{"ok":true}`
116 }
117
118 handler.OnAccessibilityTreeChange(stubCEFValue{})
119 handler.OnAccessibilityLocationChange(stubCEFValue{})
120
121 require.Len(t, writeCalls, 2)
122 require.Len(t, got, 2)
123 assert.Equal(t, accessibilityCaptureKindTree, got[0].Kind)
124 assert.Equal(t, `{"ok":true}`, got[0].JSON)
125 assert.Equal(t, len(`{"ok":true}`), got[0].Bytes)
126 assert.GreaterOrEqual(t, got[0].SerializeNanos, int64(0))
127 assert.Equal(t, accessibilityCaptureKindLocation, got[1].Kind)
128 assert.Equal(t, `{"ok":true}`, got[1].JSON)
129 assert.Equal(t, len(`{"ok":true}`), got[1].Bytes)
130 assert.GreaterOrEqual(t, got[1].SerializeNanos, int64(0))
131}
132
133func TestAccessibilityHandler_ProductionNoCaptureZeroWriteJSON(t *testing.T) {
134 calls := 0
135
136 // Factory/production path without DUMBER_A11Y_CAPTURE=1: worker stays nil,
137 // sink is truly nil, WriteJson must not run.
138 wv := &WebView{viewBridge: &Cef2gtkAdapter{}}
139 rh := newDumberRenderHandler(wv)
140 require.NotNil(t, rh)
141
142 handler, ok := rh.GetAccessibilityHandler().(*accessibilityHandler)
143 require.True(t, ok)
144 require.Nil(t, handler.sink)
145 handler.writeJSON = func(purecef.Value, purecef.JsonWriterOptions) string {
146 calls++
147 return `{}`
148 }
149
150 handler.OnAccessibilityTreeChange(stubCEFValue{})
151 handler.OnAccessibilityLocationChange(stubCEFValue{})
152 assert.Equal(t, 0, calls)
153}