Skip to content

Commit 3a85b11

Browse files
xlorneclaude
andcommitted
test: 大幅提升单元测试覆盖率(行覆盖 45% → 90%)
- 新增/补全五个模块单元测试共约 300 个用例,均以 Java 8 兼容语法编写便于双分支同步: starter(DTO/事件/事务/加密/本地 HttpServer REST 测试)、script(运行时/缓存/控制器)、 security(JWT/Redis 网关/过滤器/加解密)、data-fast(JDBC/动态 SQL/Map 视图)、 data-authorization(JDBC 代理链/列脱敏/SQL 分析) - 覆盖率:starter 51.8%→78.5%、script 64.5%→98.3%、security 68.8%→94.7%、 data-fast 32.9%→89.3%、data-authorization 28.5%→97.1% Co-Authored-By: Claude <noreply@anthropic.com>
1 parent ddc15f1 commit 3a85b11

57 files changed

Lines changed: 7734 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.codingapi.springboot.authorization.exception;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import java.sql.SQLException;
6+
7+
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
import static org.junit.jupiter.api.Assertions.assertNull;
9+
import static org.junit.jupiter.api.Assertions.assertTrue;
10+
11+
/**
12+
* NotAuthorizationException 单元测试
13+
*/
14+
class NotAuthorizationExceptionTest {
15+
16+
@Test
17+
void testDefaultConstructor() {
18+
NotAuthorizationException exception = new NotAuthorizationException();
19+
assertTrue(exception instanceof SQLException);
20+
assertNull(exception.getMessage());
21+
}
22+
23+
@Test
24+
void testConstructorWithReason() {
25+
NotAuthorizationException exception = new NotAuthorizationException("no permission");
26+
assertTrue(exception instanceof SQLException);
27+
assertEquals("no permission", exception.getMessage());
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package com.codingapi.springboot.authorization.handler;
2+
3+
import com.codingapi.springboot.authorization.interceptor.SQLExecuteState;
4+
import org.junit.jupiter.api.AfterEach;
5+
import org.junit.jupiter.api.BeforeEach;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.io.InputStream;
9+
import java.io.Reader;
10+
import java.math.BigDecimal;
11+
import java.net.URL;
12+
import java.sql.Array;
13+
import java.sql.Blob;
14+
import java.sql.Clob;
15+
import java.sql.Date;
16+
import java.sql.NClob;
17+
import java.sql.Ref;
18+
import java.sql.RowId;
19+
import java.sql.SQLXML;
20+
import java.sql.Time;
21+
import java.sql.Timestamp;
22+
23+
import static org.junit.jupiter.api.Assertions.assertEquals;
24+
import static org.junit.jupiter.api.Assertions.assertSame;
25+
import static org.mockito.ArgumentMatchers.any;
26+
import static org.mockito.ArgumentMatchers.anyBoolean;
27+
import static org.mockito.ArgumentMatchers.anyByte;
28+
import static org.mockito.ArgumentMatchers.anyDouble;
29+
import static org.mockito.ArgumentMatchers.anyFloat;
30+
import static org.mockito.ArgumentMatchers.anyInt;
31+
import static org.mockito.ArgumentMatchers.anyLong;
32+
import static org.mockito.ArgumentMatchers.anyShort;
33+
import static org.mockito.ArgumentMatchers.anyString;
34+
import static org.mockito.ArgumentMatchers.eq;
35+
import static org.mockito.Mockito.mock;
36+
import static org.mockito.Mockito.verify;
37+
import static org.mockito.Mockito.when;
38+
39+
/**
40+
* ColumnHandlerContext 单元测试
41+
* 验证上下文将各类 get 请求委托给注册的 ColumnHandler
42+
*/
43+
class ColumnHandlerContextTest {
44+
45+
private ColumnHandler columnHandler;
46+
private SQLExecuteState state;
47+
48+
@BeforeEach
49+
void setUp() {
50+
columnHandler = mock(ColumnHandler.class);
51+
ColumnHandlerContext.getInstance().setColumnHandler(columnHandler);
52+
state = SQLExecuteState.unIntercept("select 1");
53+
}
54+
55+
@AfterEach
56+
void tearDown() {
57+
// 恢复默认处理器,避免影响其他测试
58+
ColumnHandlerContext.getInstance().setColumnHandler(new DefaultColumnHandler());
59+
}
60+
61+
@Test
62+
void testDelegatesToColumnHandler() throws Exception {
63+
when(columnHandler.getString(any(), anyInt(), anyString(), anyString(), anyString())).thenReturn("s");
64+
when(columnHandler.getShort(any(), anyInt(), anyString(), anyString(), anyShort())).thenReturn((short) 1);
65+
when(columnHandler.getBoolean(any(), anyInt(), anyString(), anyString(), anyBoolean())).thenReturn(true);
66+
when(columnHandler.getByte(any(), anyInt(), anyString(), anyString(), anyByte())).thenReturn((byte) 2);
67+
when(columnHandler.getInt(any(), anyInt(), anyString(), anyString(), anyInt())).thenReturn(3);
68+
when(columnHandler.getLong(any(), anyInt(), anyString(), anyString(), anyLong())).thenReturn(4L);
69+
when(columnHandler.getFloat(any(), anyInt(), anyString(), anyString(), anyFloat())).thenReturn(5.0f);
70+
when(columnHandler.getDouble(any(), anyInt(), anyString(), anyString(), anyDouble())).thenReturn(6.0d);
71+
when(columnHandler.getBigDecimal(any(), anyInt(), anyString(), anyString(), any(BigDecimal.class)))
72+
.thenReturn(BigDecimal.ONE);
73+
when(columnHandler.getBytes(any(), anyInt(), anyString(), anyString(), any()))
74+
.thenReturn(new byte[]{1});
75+
Timestamp timestamp = new Timestamp(1000L);
76+
when(columnHandler.getTimestamp(any(), anyInt(), anyString(), anyString(), any()))
77+
.thenReturn(timestamp);
78+
Time time = new Time(1000L);
79+
when(columnHandler.getTime(any(), anyInt(), anyString(), anyString(), any())).thenReturn(time);
80+
Date date = new Date(1000L);
81+
when(columnHandler.getDate(any(), anyInt(), anyString(), anyString(), any())).thenReturn(date);
82+
InputStream inputStream = mock(InputStream.class);
83+
when(columnHandler.getAsciiStream(any(), anyInt(), anyString(), anyString(), any()))
84+
.thenReturn(inputStream);
85+
when(columnHandler.getUnicodeStream(any(), anyInt(), anyString(), anyString(), any()))
86+
.thenReturn(inputStream);
87+
when(columnHandler.getBinaryStream(any(), anyInt(), anyString(), anyString(), any()))
88+
.thenReturn(inputStream);
89+
when(columnHandler.getObject(any(), anyInt(), anyString(), anyString(), any())).thenReturn("obj");
90+
Reader reader = mock(Reader.class);
91+
when(columnHandler.getCharacterStream(any(), anyInt(), anyString(), anyString(), any()))
92+
.thenReturn(reader);
93+
when(columnHandler.getNCharacterStream(any(), anyInt(), anyString(), anyString(), any()))
94+
.thenReturn(reader);
95+
Ref ref = mock(Ref.class);
96+
when(columnHandler.getRef(any(), anyInt(), anyString(), anyString(), any())).thenReturn(ref);
97+
Blob blob = mock(Blob.class);
98+
when(columnHandler.getBlob(any(), anyInt(), anyString(), anyString(), any())).thenReturn(blob);
99+
Clob clob = mock(Clob.class);
100+
when(columnHandler.getClob(any(), anyInt(), anyString(), anyString(), any())).thenReturn(clob);
101+
Array array = mock(Array.class);
102+
when(columnHandler.getArray(any(), anyInt(), anyString(), anyString(), any())).thenReturn(array);
103+
URL url = mock(URL.class);
104+
when(columnHandler.getURL(any(), anyInt(), anyString(), anyString(), any())).thenReturn(url);
105+
NClob nClob = mock(NClob.class);
106+
when(columnHandler.getNClob(any(), anyInt(), anyString(), anyString(), any())).thenReturn(nClob);
107+
SQLXML sqlxml = mock(SQLXML.class);
108+
when(columnHandler.getSQLXML(any(), anyInt(), anyString(), anyString(), any()))
109+
.thenReturn(sqlxml);
110+
when(columnHandler.getNString(any(), anyInt(), anyString(), anyString(), anyString())).thenReturn("ns");
111+
RowId rowId = mock(RowId.class);
112+
when(columnHandler.getRowId(any(), anyInt(), anyString(), anyString(), any())).thenReturn(rowId);
113+
when(columnHandler.getObject(any(), anyInt(), anyString(), anyString(), any(), eq(String.class)))
114+
.thenReturn("typed");
115+
116+
ColumnHandlerContext context = ColumnHandlerContext.getInstance();
117+
118+
assertEquals("s", context.getString(state, 1, "t", "c", "v"));
119+
assertEquals((short) 1, context.getShort(state, 1, "t", "c", (short) 0));
120+
assertEquals(true, context.getBoolean(state, 1, "t", "c", false));
121+
assertEquals((byte) 2, context.getByte(state, 1, "t", "c", (byte) 0));
122+
assertEquals(3, context.getInt(state, 1, "t", "c", 0));
123+
assertEquals(4L, context.getLong(state, 1, "t", "c", 0L));
124+
assertEquals(5.0f, context.getFloat(state, 1, "t", "c", 0f));
125+
assertEquals(6.0d, context.getDouble(state, 1, "t", "c", 0d));
126+
assertEquals(BigDecimal.ONE, context.getBigDecimal(state, 1, "t", "c", BigDecimal.ZERO));
127+
assertSame(timestamp, context.getTimestamp(state, 1, "t", "c", null));
128+
assertSame(time, context.getTime(state, 1, "t", "c", null));
129+
assertSame(date, context.getDate(state, 1, "t", "c", null));
130+
assertSame(inputStream, context.getAsciiStream(state, 1, "t", "c", null));
131+
assertSame(inputStream, context.getUnicodeStream(state, 1, "t", "c", null));
132+
assertSame(inputStream, context.getBinaryStream(state, 1, "t", "c", null));
133+
assertEquals("obj", context.getObject(state, 1, "t", "c", null));
134+
assertSame(reader, context.getCharacterStream(state, 1, "t", "c", null));
135+
assertSame(reader, context.getNCharacterStream(state, 1, "t", "c", null));
136+
assertSame(ref, context.getRef(state, 1, "t", "c", null));
137+
assertSame(blob, context.getBlob(state, 1, "t", "c", null));
138+
assertSame(clob, context.getClob(state, 1, "t", "c", null));
139+
assertSame(array, context.getArray(state, 1, "t", "c", null));
140+
assertSame(url, context.getURL(state, 1, "t", "c", null));
141+
assertSame(nClob, context.getNClob(state, 1, "t", "c", null));
142+
assertSame(sqlxml, context.getSQLXML(state, 1, "t", "c", null));
143+
assertEquals("ns", context.getNString(state, 1, "t", "c", "v"));
144+
assertSame(rowId, context.getRowId(state, 1, "t", "c", null));
145+
assertEquals("typed", context.getObject(state, 1, "t", "c", "v", String.class));
146+
assertEquals(1, context.getBytes(state, 1, "t", "c", null).length);
147+
148+
// 验证委托时参数透传
149+
verify(columnHandler).getString(state, 1, "t", "c", "v");
150+
verify(columnHandler).getInt(state, 1, "t", "c", 0);
151+
verify(columnHandler).getObject(state, 1, "t", "c", "v", String.class);
152+
}
153+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.codingapi.springboot.authorization.handler;
2+
3+
import com.codingapi.springboot.authorization.condition.IConditionSQL;
4+
import com.codingapi.springboot.authorization.condition.JoinConditionSQL;
5+
import com.codingapi.springboot.authorization.condition.WhereConditionSQL;
6+
import org.junit.jupiter.api.Test;
7+
8+
import static org.junit.jupiter.api.Assertions.assertEquals;
9+
import static org.junit.jupiter.api.Assertions.assertNotNull;
10+
import static org.junit.jupiter.api.Assertions.assertNull;
11+
import static org.junit.jupiter.api.Assertions.assertTrue;
12+
13+
/**
14+
* Condition 单元测试
15+
*/
16+
class ConditionTest {
17+
18+
@Test
19+
void testEmptyConstructor() {
20+
Condition condition = new Condition();
21+
assertNotNull(condition.getConditionList());
22+
assertEquals(0, condition.getConditionList().size());
23+
}
24+
25+
@Test
26+
void testConditionWithWhereSql() {
27+
Condition condition = new Condition("t.id = 1");
28+
assertEquals(1, condition.getConditionList().size());
29+
IConditionSQL conditionSQL = condition.getConditionList().get(0);
30+
assertTrue(conditionSQL instanceof WhereConditionSQL);
31+
assertEquals("t.id = 1", ((WhereConditionSQL) conditionSQL).getCondition());
32+
}
33+
34+
@Test
35+
void testAddConditionSql() {
36+
Condition condition = new Condition();
37+
condition.addConditionSQL(new WhereConditionSQL("t.id = 1"));
38+
condition.addConditionSQL(new JoinConditionSQL(JoinConditionSQL.Type.INNER, "t_unit", "u", "u.id = t.id"));
39+
assertEquals(2, condition.getConditionList().size());
40+
}
41+
42+
@Test
43+
void testCustomCondition() {
44+
Condition condition = Condition.customCondition("t.id = 1");
45+
assertEquals(1, condition.getConditionList().size());
46+
WhereConditionSQL whereConditionSQL = (WhereConditionSQL) condition.getConditionList().get(0);
47+
assertEquals("t.id = 1", whereConditionSQL.getCondition());
48+
}
49+
50+
@Test
51+
void testFormatCondition() {
52+
Condition condition = Condition.formatCondition("%s.id = %d", "u", 10);
53+
WhereConditionSQL whereConditionSQL = (WhereConditionSQL) condition.getConditionList().get(0);
54+
assertEquals("u.id = 10", whereConditionSQL.getCondition());
55+
}
56+
57+
@Test
58+
void testEmptyConditionReturnsNull() {
59+
assertNull(Condition.emptyCondition());
60+
}
61+
62+
@Test
63+
void testDefaultCondition() {
64+
Condition condition = Condition.defaultCondition();
65+
WhereConditionSQL whereConditionSQL = (WhereConditionSQL) condition.getConditionList().get(0);
66+
assertEquals("1=1", whereConditionSQL.getCondition());
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package com.codingapi.springboot.authorization.handler;
2+
3+
import com.codingapi.springboot.authorization.DataAuthorizationContext;
4+
import com.codingapi.springboot.authorization.filter.DefaultDataAuthorizationFilter;
5+
import com.codingapi.springboot.authorization.interceptor.SQLExecuteState;
6+
import com.codingapi.springboot.authorization.interceptor.SQLRunningContext;
7+
import org.junit.jupiter.api.AfterEach;
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
11+
import java.io.InputStream;
12+
import java.io.Reader;
13+
import java.math.BigDecimal;
14+
import java.net.URL;
15+
import java.sql.Array;
16+
import java.sql.Blob;
17+
import java.sql.Clob;
18+
import java.sql.Date;
19+
import java.sql.NClob;
20+
import java.sql.Ref;
21+
import java.sql.RowId;
22+
import java.sql.SQLXML;
23+
import java.sql.Time;
24+
import java.sql.Timestamp;
25+
26+
import static org.junit.jupiter.api.Assertions.assertEquals;
27+
import static org.junit.jupiter.api.Assertions.assertSame;
28+
import static org.junit.jupiter.api.Assertions.assertTrue;
29+
import static org.mockito.Mockito.mock;
30+
31+
/**
32+
* DefaultColumnHandler 单元测试
33+
* 验证默认列处理器将请求委托给 DataAuthorizationContext.columnAuthorization:
34+
* 未拦截时原值返回;拦截且过滤器支持时返回加工后的值
35+
*/
36+
class DefaultColumnHandlerTest {
37+
38+
private DefaultColumnHandler handler;
39+
40+
@BeforeEach
41+
void setUp() {
42+
DataAuthorizationContext.getInstance().clearDataAuthorizationFilters();
43+
handler = new DefaultColumnHandler();
44+
}
45+
46+
@AfterEach
47+
void tearDown() {
48+
DataAuthorizationContext.getInstance().clearDataAuthorizationFilters();
49+
}
50+
51+
@Test
52+
void testUnInterceptStateReturnsOriginalValues() throws Exception {
53+
SQLExecuteState state = SQLExecuteState.unIntercept("select 1");
54+
InputStream inputStream = mock(InputStream.class);
55+
Reader reader = mock(Reader.class);
56+
Ref ref = mock(Ref.class);
57+
Blob blob = mock(Blob.class);
58+
Clob clob = mock(Clob.class);
59+
Array array = mock(Array.class);
60+
URL url = mock(URL.class);
61+
NClob nClob = mock(NClob.class);
62+
SQLXML sqlxml = mock(SQLXML.class);
63+
RowId rowId = mock(RowId.class);
64+
Date date = new Date(1000L);
65+
Time time = new Time(1000L);
66+
Timestamp timestamp = new Timestamp(1000L);
67+
byte[] bytes = new byte[]{1};
68+
69+
assertEquals("v", handler.getString(state, 1, "t", "c", "v"));
70+
assertEquals(true, handler.getBoolean(state, 1, "t", "c", true));
71+
assertEquals((byte) 1, handler.getByte(state, 1, "t", "c", (byte) 1));
72+
assertEquals((short) 1, handler.getShort(state, 1, "t", "c", (short) 1));
73+
assertEquals(1, handler.getInt(state, 1, "t", "c", 1));
74+
assertEquals(1L, handler.getLong(state, 1, "t", "c", 1L));
75+
assertEquals(1.0f, handler.getFloat(state, 1, "t", "c", 1.0f));
76+
assertEquals(1.0d, handler.getDouble(state, 1, "t", "c", 1.0d));
77+
assertEquals(BigDecimal.ONE, handler.getBigDecimal(state, 1, "t", "c", BigDecimal.ONE));
78+
assertSame(bytes, handler.getBytes(state, 1, "t", "c", bytes));
79+
assertSame(date, handler.getDate(state, 1, "t", "c", date));
80+
assertSame(time, handler.getTime(state, 1, "t", "c", time));
81+
assertSame(timestamp, handler.getTimestamp(state, 1, "t", "c", timestamp));
82+
assertSame(inputStream, handler.getAsciiStream(state, 1, "t", "c", inputStream));
83+
assertSame(inputStream, handler.getUnicodeStream(state, 1, "t", "c", inputStream));
84+
assertSame(inputStream, handler.getBinaryStream(state, 1, "t", "c", inputStream));
85+
assertEquals("obj", handler.getObject(state, 1, "t", "c", "obj"));
86+
assertSame(reader, handler.getCharacterStream(state, 1, "t", "c", reader));
87+
assertSame(ref, handler.getRef(state, 1, "t", "c", ref));
88+
assertSame(blob, handler.getBlob(state, 1, "t", "c", blob));
89+
assertSame(clob, handler.getClob(state, 1, "t", "c", clob));
90+
assertSame(array, handler.getArray(state, 1, "t", "c", array));
91+
assertSame(url, handler.getURL(state, 1, "t", "c", url));
92+
assertSame(nClob, handler.getNClob(state, 1, "t", "c", nClob));
93+
assertSame(sqlxml, handler.getSQLXML(state, 1, "t", "c", sqlxml));
94+
assertEquals("nv", handler.getNString(state, 1, "t", "c", "nv"));
95+
assertSame(reader, handler.getNCharacterStream(state, 1, "t", "c", reader));
96+
assertSame(rowId, handler.getRowId(state, 1, "t", "c", rowId));
97+
assertEquals("typed", handler.getObject(state, 1, "t", "c", "typed", String.class));
98+
}
99+
100+
@Test
101+
void testInterceptStateAppliesColumnAuthorization() throws Exception {
102+
DataAuthorizationContext.getInstance().addDataAuthorizationFilter(new DefaultDataAuthorizationFilter() {
103+
@Override
104+
public boolean supportRowAuthorization(String tableName, String tableAlias) {
105+
return "t_user".equalsIgnoreCase(tableName);
106+
}
107+
108+
@Override
109+
public Condition rowAuthorization(String tableName, String tableAlias) {
110+
return Condition.formatCondition("%s.id > 100", tableAlias);
111+
}
112+
113+
@Override
114+
public boolean supportColumnAuthorization(String tableName, String columnName, Object value) {
115+
return "t_user".equalsIgnoreCase(tableName);
116+
}
117+
118+
@SuppressWarnings("unchecked")
119+
@Override
120+
public <T> T columnAuthorization(String tableName, String columnName, T value) {
121+
if (value instanceof String) {
122+
return (T) ("MASKED-" + value);
123+
}
124+
if (value instanceof Integer) {
125+
return (T) Integer.valueOf(-1);
126+
}
127+
return value;
128+
}
129+
});
130+
131+
SQLExecuteState state = SQLRunningContext.getInstance().intercept("select name from t_user");
132+
assertTrue(state.hasIntercept());
133+
134+
assertEquals("MASKED-raw", handler.getString(state, 1, "t_user", "name", "raw"));
135+
assertEquals(Integer.valueOf(-1), Integer.valueOf(handler.getInt(state, 1, "t_user", "id", 1)));
136+
assertEquals("MASKED-nv", handler.getNString(state, 1, "t_user", "name", "nv"));
137+
assertEquals("MASKED-obj", handler.getObject(state, 1, "t_user", "name", "obj"));
138+
assertEquals("MASKED-typed", handler.getObject(state, 1, "t_user", "name", "typed", String.class));
139+
}
140+
}

0 commit comments

Comments
 (0)