1
use axum::{
2
    Router,
3
    body::Body,
4
    http::Request,
5
    routing::{get, post},
6
};
7
use serde_json::json;
8
use tower::ServiceExt;
9

            
10
use crate::common::{create_mock_jwt_auth, create_mock_user, create_test_app_state};
11

            
12
#[tokio::test]
13
3
async fn test_tag_create_without_auth() {
14
2
    let app_state = create_test_app_state().await;
15
2
    let app = Router::new()
16
2
        .route(
17
2
            "/tag/create/submit",
18
2
            post(web::pages::tag::create::create_tag),
19
        )
20
2
        .with_state(app_state);
21

            
22
2
    let tag_data = json!({
23
2
        "tag_name": "Test Tag",
24
2
        "tag_value": "test_value",
25
2
        "description": null
26
    });
27

            
28
2
    let response = app
29
2
        .oneshot(
30
2
            Request::builder()
31
2
                .method("POST")
32
2
                .uri("/tag/create/submit")
33
2
                .header("content-type", "application/json")
34
2
                .body(Body::from(tag_data.to_string()))
35
2
                .unwrap(),
36
2
        )
37
2
        .await
38
2
        .unwrap();
39

            
40
3
    assert!(response.status().is_client_error() || response.status().is_server_error());
41
2
}
42

            
43
#[tokio::test]
44
3
async fn test_tag_create_with_invalid_json() {
45
2
    let app_state = create_test_app_state().await;
46
2
    let app = Router::new()
47
2
        .route(
48
2
            "/tag/create/submit",
49
2
            post(web::pages::tag::create::create_tag),
50
        )
51
2
        .with_state(app_state);
52

            
53
2
    let response = app
54
2
        .oneshot(
55
2
            Request::builder()
56
2
                .method("POST")
57
2
                .uri("/tag/create/submit")
58
2
                .header("content-type", "application/json")
59
2
                .body(Body::from("invalid json"))
60
2
                .unwrap(),
61
2
        )
62
2
        .await
63
2
        .unwrap();
64

            
65
3
    assert!(response.status().is_client_error() || response.status().is_server_error());
66
2
}
67

            
68
#[tokio::test]
69
3
async fn test_tag_create_with_mock_auth() {
70
2
    let app_state = create_test_app_state().await;
71
2
    let mock_user = create_mock_user();
72
2
    let jwt_auth = create_mock_jwt_auth(mock_user);
73

            
74
2
    let app = Router::new()
75
2
        .route(
76
2
            "/tag/create/submit",
77
2
            post(web::pages::tag::create::create_tag),
78
        )
79
2
        .layer(axum::middleware::from_fn_with_state(
80
2
            app_state.clone(),
81
2
            move |mut req: axum::http::Request<Body>, next: axum::middleware::Next| {
82
2
                let jwt_auth = jwt_auth.clone();
83
2
                async move {
84
2
                    req.extensions_mut().insert(jwt_auth);
85
2
                    next.run(req).await
86
2
                }
87
2
            },
88
        ))
89
2
        .with_state(app_state.clone());
90

            
91
2
    let tag_data = json!({
92
2
        "tag_name": "Test Tag",
93
2
        "tag_value": "test_value",
94
2
        "description": null
95
    });
96

            
97
2
    let response = app
98
2
        .oneshot(
99
2
            Request::builder()
100
2
                .method("POST")
101
2
                .uri("/tag/create/submit")
102
2
                .header("content-type", "application/json")
103
2
                .body(Body::from(tag_data.to_string()))
104
2
                .unwrap(),
105
2
        )
106
2
        .await
107
2
        .unwrap();
108

            
109
3
    assert!(
110
3
        response.status().is_success() || response.status().is_server_error(),
111
2
        "Expected success or server error, got: {}",
112
2
        response.status()
113
2
    );
114
2
}
115

            
116
#[tokio::test]
117
3
async fn test_tag_create_with_description() {
118
2
    let app_state = create_test_app_state().await;
119
2
    let mock_user = create_mock_user();
120
2
    let jwt_auth = create_mock_jwt_auth(mock_user);
121

            
122
2
    let app = Router::new()
123
2
        .route(
124
2
            "/tag/create/submit",
125
2
            post(web::pages::tag::create::create_tag),
126
        )
127
2
        .layer(axum::middleware::from_fn_with_state(
128
2
            app_state.clone(),
129
2
            move |mut req: axum::http::Request<Body>, next: axum::middleware::Next| {
130
2
                let jwt_auth = jwt_auth.clone();
131
2
                async move {
132
2
                    req.extensions_mut().insert(jwt_auth);
133
2
                    next.run(req).await
134
2
                }
135
2
            },
136
        ))
137
2
        .with_state(app_state.clone());
138

            
139
2
    let tag_data = json!({
140
2
        "tag_name": "Category",
141
2
        "tag_value": "category1",
142
2
        "description": "Test description"
143
    });
144

            
145
2
    let response = app
146
2
        .oneshot(
147
2
            Request::builder()
148
2
                .method("POST")
149
2
                .uri("/tag/create/submit")
150
2
                .header("content-type", "application/json")
151
2
                .body(Body::from(tag_data.to_string()))
152
2
                .unwrap(),
153
2
        )
154
2
        .await
155
2
        .unwrap();
156

            
157
3
    assert!(
158
3
        response.status().is_success() || response.status().is_server_error(),
159
2
        "Expected success or server error, got: {}",
160
2
        response.status()
161
2
    );
162
2
}
163

            
164
#[tokio::test]
165
3
async fn test_tag_list_without_auth() {
166
2
    let app_state = create_test_app_state().await;
167
2
    let app = Router::new()
168
2
        .route("/tag/list", get(web::pages::tag::list::tag_table))
169
2
        .with_state(app_state);
170

            
171
2
    let response = app
172
2
        .oneshot(
173
2
            Request::builder()
174
2
                .method("GET")
175
2
                .uri("/tag/list")
176
2
                .body(Body::empty())
177
2
                .unwrap(),
178
2
        )
179
2
        .await
180
2
        .unwrap();
181

            
182
3
    assert!(response.status().is_client_error() || response.status().is_server_error());
183
2
}
184

            
185
#[tokio::test]
186
3
async fn test_tag_list_with_mock_auth() {
187
2
    let app_state = create_test_app_state().await;
188
2
    let mock_user = create_mock_user();
189
2
    let jwt_auth = create_mock_jwt_auth(mock_user);
190

            
191
2
    let app = Router::new()
192
2
        .route("/tag/list", get(web::pages::tag::list::tag_table))
193
2
        .layer(axum::middleware::from_fn_with_state(
194
2
            app_state.clone(),
195
2
            move |mut req: axum::http::Request<Body>, next: axum::middleware::Next| {
196
2
                let jwt_auth = jwt_auth.clone();
197
2
                async move {
198
2
                    req.extensions_mut().insert(jwt_auth);
199
2
                    next.run(req).await
200
2
                }
201
2
            },
202
        ))
203
2
        .with_state(app_state.clone());
204

            
205
2
    let response = app
206
2
        .oneshot(
207
2
            Request::builder()
208
2
                .method("GET")
209
2
                .uri("/tag/list")
210
2
                .body(Body::empty())
211
2
                .unwrap(),
212
2
        )
213
2
        .await
214
2
        .unwrap();
215

            
216
2
    assert!(
217
2
        response.status().is_success() || response.status().is_server_error(),
218
        "Expected success or server error, got: {}",
219
        response.status()
220
    );
221

            
222
3
    if let Some(content_type) = response.headers().get("content-type") {
223
3
        let content_type_str = content_type.to_str().unwrap_or("");
224
3
        assert!(
225
3
            content_type_str.contains("text/") || content_type_str.is_empty(),
226
2
            "Expected text content type, got: {}",
227
2
            content_type_str
228
2
        );
229
2
    }
230
2
}
231

            
232
#[tokio::test]
233
3
async fn test_tag_edit_without_auth() {
234
2
    let app_state = create_test_app_state().await;
235
2
    let app = Router::new()
236
2
        .route("/tag/edit/submit", post(web::pages::tag::edit::edit_tag))
237
2
        .with_state(app_state);
238

            
239
2
    let tag_data = json!({
240
2
        "id": "550e8400-e29b-41d4-a716-446655440000",
241
2
        "tag_name": "Updated Tag",
242
2
        "tag_value": "updated_value",
243
2
        "description": "Updated description"
244
    });
245

            
246
2
    let response = app
247
2
        .oneshot(
248
2
            Request::builder()
249
2
                .method("POST")
250
2
                .uri("/tag/edit/submit")
251
2
                .header("content-type", "application/json")
252
2
                .body(Body::from(tag_data.to_string()))
253
2
                .unwrap(),
254
2
        )
255
2
        .await
256
2
        .unwrap();
257

            
258
3
    assert!(response.status().is_client_error() || response.status().is_server_error());
259
2
}
260

            
261
#[tokio::test]
262
3
async fn test_tag_edit_with_mock_auth() {
263
2
    let app_state = create_test_app_state().await;
264
2
    let mock_user = create_mock_user();
265
2
    let jwt_auth = create_mock_jwt_auth(mock_user);
266

            
267
2
    let app = Router::new()
268
2
        .route("/tag/edit/submit", post(web::pages::tag::edit::edit_tag))
269
2
        .layer(axum::middleware::from_fn_with_state(
270
2
            app_state.clone(),
271
2
            move |mut req: axum::http::Request<Body>, next: axum::middleware::Next| {
272
2
                let jwt_auth = jwt_auth.clone();
273
2
                async move {
274
2
                    req.extensions_mut().insert(jwt_auth);
275
2
                    next.run(req).await
276
2
                }
277
2
            },
278
        ))
279
2
        .with_state(app_state.clone());
280

            
281
2
    let tag_data = json!({
282
2
        "id": "550e8400-e29b-41d4-a716-446655440000",
283
2
        "tag_name": "Updated Tag",
284
2
        "tag_value": "updated_value",
285
2
        "description": "Updated description"
286
    });
287

            
288
2
    let response = app
289
2
        .oneshot(
290
2
            Request::builder()
291
2
                .method("POST")
292
2
                .uri("/tag/edit/submit")
293
2
                .header("content-type", "application/json")
294
2
                .body(Body::from(tag_data.to_string()))
295
2
                .unwrap(),
296
2
        )
297
2
        .await
298
2
        .unwrap();
299

            
300
3
    assert!(
301
3
        response.status().is_success() || response.status().is_server_error(),
302
2
        "Expected success or server error, got: {}",
303
2
        response.status()
304
2
    );
305
2
}
306

            
307
#[tokio::test]
308
3
async fn test_tag_delete_without_auth() {
309
2
    let app_state = create_test_app_state().await;
310
2
    let app = Router::new()
311
2
        .route("/tag/delete/{id}", post(web::pages::tag::edit::delete_tag))
312
2
        .with_state(app_state);
313

            
314
2
    let response = app
315
2
        .oneshot(
316
2
            Request::builder()
317
2
                .method("POST")
318
2
                .uri("/tag/delete/550e8400-e29b-41d4-a716-446655440000")
319
2
                .body(Body::empty())
320
2
                .unwrap(),
321
2
        )
322
2
        .await
323
2
        .unwrap();
324

            
325
3
    assert!(response.status().is_client_error() || response.status().is_server_error());
326
2
}
327

            
328
#[tokio::test]
329
3
async fn test_tag_delete_with_mock_auth() {
330
2
    let app_state = create_test_app_state().await;
331
2
    let mock_user = create_mock_user();
332
2
    let jwt_auth = create_mock_jwt_auth(mock_user);
333

            
334
2
    let app = Router::new()
335
2
        .route("/tag/delete/{id}", post(web::pages::tag::edit::delete_tag))
336
2
        .layer(axum::middleware::from_fn_with_state(
337
2
            app_state.clone(),
338
2
            move |mut req: axum::http::Request<Body>, next: axum::middleware::Next| {
339
2
                let jwt_auth = jwt_auth.clone();
340
2
                async move {
341
2
                    req.extensions_mut().insert(jwt_auth);
342
2
                    next.run(req).await
343
2
                }
344
2
            },
345
        ))
346
2
        .with_state(app_state.clone());
347

            
348
2
    let response = app
349
2
        .oneshot(
350
2
            Request::builder()
351
2
                .method("POST")
352
2
                .uri("/tag/delete/550e8400-e29b-41d4-a716-446655440000")
353
2
                .body(Body::empty())
354
2
                .unwrap(),
355
2
        )
356
2
        .await
357
2
        .unwrap();
358

            
359
3
    assert!(
360
3
        response.status().is_success() || response.status().is_server_error(),
361
2
        "Expected success or server error, got: {}",
362
2
        response.status()
363
2
    );
364
2
}
365

            
366
#[tokio::test]
367
3
async fn test_tag_edit_remove_description() {
368
2
    let app_state = create_test_app_state().await;
369
2
    let mock_user = create_mock_user();
370
2
    let jwt_auth = create_mock_jwt_auth(mock_user);
371

            
372
2
    let app = Router::new()
373
2
        .route("/tag/edit/submit", post(web::pages::tag::edit::edit_tag))
374
2
        .layer(axum::middleware::from_fn_with_state(
375
2
            app_state.clone(),
376
2
            move |mut req: axum::http::Request<Body>, next: axum::middleware::Next| {
377
2
                let jwt_auth = jwt_auth.clone();
378
2
                async move {
379
2
                    req.extensions_mut().insert(jwt_auth);
380
2
                    next.run(req).await
381
2
                }
382
2
            },
383
        ))
384
2
        .with_state(app_state.clone());
385

            
386
2
    let tag_data = json!({
387
2
        "id": "550e8400-e29b-41d4-a716-446655440000",
388
2
        "tag_name": "Tag Name",
389
2
        "tag_value": "tag_value",
390
2
        "description": null
391
    });
392

            
393
2
    let response = app
394
2
        .oneshot(
395
2
            Request::builder()
396
2
                .method("POST")
397
2
                .uri("/tag/edit/submit")
398
2
                .header("content-type", "application/json")
399
2
                .body(Body::from(tag_data.to_string()))
400
2
                .unwrap(),
401
2
        )
402
2
        .await
403
2
        .unwrap();
404

            
405
3
    assert!(
406
3
        response.status().is_success() || response.status().is_server_error(),
407
2
        "Expected success or server error, got: {}",
408
2
        response.status()
409
2
    );
410
2
}
411

            
412
#[tokio::test]
413
3
async fn test_transaction_tag_create_without_auth() {
414
2
    let app_state = create_test_app_state().await;
415
2
    let app = Router::new()
416
2
        .route(
417
2
            "/transaction/{id}/tag/create/submit",
418
2
            post(web::pages::tag::create::create_transaction_tag),
419
        )
420
2
        .with_state(app_state);
421

            
422
2
    let tag_data = json!({
423
2
        "tag_name": "Category",
424
2
        "tag_value": "expense",
425
2
        "description": "Transaction category"
426
    });
427

            
428
2
    let response = app
429
2
        .oneshot(
430
2
            Request::builder()
431
2
                .method("POST")
432
2
                .uri("/transaction/550e8400-e29b-41d4-a716-446655440000/tag/create/submit")
433
2
                .header("content-type", "application/json")
434
2
                .body(Body::from(tag_data.to_string()))
435
2
                .unwrap(),
436
2
        )
437
2
        .await
438
2
        .unwrap();
439

            
440
3
    assert!(response.status().is_client_error() || response.status().is_server_error());
441
2
}
442

            
443
#[tokio::test]
444
3
async fn test_transaction_tag_create_with_mock_auth() {
445
2
    let app_state = create_test_app_state().await;
446
2
    let mock_user = create_mock_user();
447
2
    let jwt_auth = create_mock_jwt_auth(mock_user);
448

            
449
2
    let app = Router::new()
450
2
        .route(
451
2
            "/transaction/{id}/tag/create/submit",
452
2
            post(web::pages::tag::create::create_transaction_tag),
453
        )
454
2
        .layer(axum::middleware::from_fn_with_state(
455
2
            app_state.clone(),
456
2
            move |mut req: axum::http::Request<Body>, next: axum::middleware::Next| {
457
2
                let jwt_auth = jwt_auth.clone();
458
2
                async move {
459
2
                    req.extensions_mut().insert(jwt_auth);
460
2
                    next.run(req).await
461
2
                }
462
2
            },
463
        ))
464
2
        .with_state(app_state.clone());
465

            
466
2
    let tag_data = json!({
467
2
        "tag_name": "Category",
468
2
        "tag_value": "expense",
469
2
        "description": "Transaction category"
470
    });
471

            
472
2
    let response = app
473
2
        .oneshot(
474
2
            Request::builder()
475
2
                .method("POST")
476
2
                .uri("/transaction/550e8400-e29b-41d4-a716-446655440000/tag/create/submit")
477
2
                .header("content-type", "application/json")
478
2
                .body(Body::from(tag_data.to_string()))
479
2
                .unwrap(),
480
2
        )
481
2
        .await
482
2
        .unwrap();
483

            
484
3
    assert!(
485
3
        response.status().is_success() || response.status().is_server_error(),
486
2
        "Expected success or server error, got: {}",
487
2
        response.status()
488
2
    );
489
2
}
490

            
491
#[tokio::test]
492
3
async fn test_transaction_tag_create_invalid_uuid() {
493
2
    let app_state = create_test_app_state().await;
494
2
    let mock_user = create_mock_user();
495
2
    let jwt_auth = create_mock_jwt_auth(mock_user);
496

            
497
2
    let app = Router::new()
498
2
        .route(
499
2
            "/transaction/{id}/tag/create/submit",
500
2
            post(web::pages::tag::create::create_transaction_tag),
501
        )
502
2
        .layer(axum::middleware::from_fn_with_state(
503
2
            app_state.clone(),
504
2
            move |mut req: axum::http::Request<Body>, next: axum::middleware::Next| {
505
2
                let jwt_auth = jwt_auth.clone();
506
2
                async move {
507
2
                    req.extensions_mut().insert(jwt_auth);
508
2
                    next.run(req).await
509
2
                }
510
2
            },
511
        ))
512
2
        .with_state(app_state.clone());
513

            
514
2
    let tag_data = json!({
515
2
        "tag_name": "Category",
516
2
        "tag_value": "expense",
517
2
        "description": null
518
    });
519

            
520
2
    let response = app
521
2
        .oneshot(
522
2
            Request::builder()
523
2
                .method("POST")
524
2
                .uri("/transaction/invalid-uuid/tag/create/submit")
525
2
                .header("content-type", "application/json")
526
2
                .body(Body::from(tag_data.to_string()))
527
2
                .unwrap(),
528
2
        )
529
2
        .await
530
2
        .unwrap();
531

            
532
3
    assert_eq!(response.status(), axum::http::StatusCode::BAD_REQUEST);
533
2
}