Compare commits
883 Commits
Author | SHA1 | Date |
---|---|---|
Dean Karn | f5e5146b31 | 2 years ago |
Cyro Dubeux | 56e2f31322 | 2 years ago |
Joselito Viveiros Nogueira Filho | e9f2d9f21a | 2 years ago |
Eduardo Mello | b43d437012 | 2 years ago |
João Fonseca | 58d420de41 | 2 years ago |
Aleksander Dejewski | c6f8637983 | 2 years ago |
Gatis Rīders | f6f934c4e9 | 2 years ago |
konstantin | ae3e728763 | 2 years ago |
Tanryberdi | 0665b9518a | 2 years ago |
jnst | 21b88d1a25 | 2 years ago |
jnst | 4f5cf1d499 | 2 years ago |
Kmilo Denis González | 2f3efda84f | 2 years ago |
brent s | 2e43671001 | 2 years ago |
just Alan | f560fd4e07 | 2 years ago |
Yasoob Haider | 29d50ba963 | 2 years ago |
zemzale | 1c1f70d35b | 2 years ago |
Yann Salaün | cc768b176d | 2 years ago |
Alberto Forcato | 3ee65f8c59 | 2 years ago |
Owen Gong | 89b91cea99 | 2 years ago |
Vijay Nallagatla | f2078f7696 | 2 years ago |
Arthur Jenoudet | ef342b6f7c | 2 years ago |
Dean Karn | f3086daf63 | 2 years ago |
Vitor Hugo | 75ba9f6a84 | 2 years ago |
Dean Karn | 13ad6f5b30 | 2 years ago |
Simon Tremblay | c242c49c02 | 2 years ago |
Dean Karn | f17b3458fa | 2 years ago |
Dean Karn | d1178535f7 | 2 years ago |
sgallizia | 72a3e75460 | 2 years ago |
Phil Porada | c0b3430b1f | 2 years ago |
Mohamed Sohail | b95730fb11 | 2 years ago |
Dean Karn | 8f07b03682 | 2 years ago |
Roberto Ramírez | 7edc63a0be | 2 years ago |
Marc Brugger | 3201fe42fe | 2 years ago |
wjl110 | 5aa5f93593 | 2 years ago |
tomaisthorpe | f036dd475d | 2 years ago |
Dean Karn | c7e0172e0f | 2 years ago |
Vaibhav Dighe | 1e8c614c2a | 2 years ago |
Dean Karn | 9e2ea40380 | 3 years ago |
Dean Karn | 29bf2a5bd0 | 3 years ago |
Dean Karn | 02c12dd7ef | 3 years ago |
Leo Liang | d0d0c355aa | 3 years ago |
Jason.Zhang | d3e4be3e44 | 3 years ago |
gosua | 99922fccc7 | 3 years ago |
Sec Cake | 4f55647bd7 | 3 years ago |
mrkongo | 39aa2e3a27 | 3 years ago |
Vuong | 7fa836dc0a | 3 years ago |
Ayoob Mohammed | 21a103f428 | 3 years ago |
Eduardo Mello | e3f29bf088 | 3 years ago |
Renato Alves Torres | d37da5e53c | 3 years ago |
Ciprian | 0a26ee57e4 | 3 years ago |
Lauris BH | f09500fca7 | 3 years ago |
Massimo Costa | 090afeb8ac | 3 years ago |
XIE Long | af72f63d39 | 3 years ago |
Stefan Dillenburg | f2d3ff7f98 | 3 years ago |
hehe.bu | aea8782168 | 3 years ago |
Sol | 24b5175a34 | 3 years ago |
NgeKaworu | bc9f9dd2eb | 3 years ago |
alessmar | dd2857a4cb | 3 years ago |
Dean Karn | bb30072b48 | 3 years ago |
Jacob Hochstetler | c0195b2b40 | 3 years ago |
Dean Karn | 58d5778b18 | 3 years ago |
Johannes | 3e49fe4eb8 | 3 years ago |
Anmar85 | dd2de9c1f7 | 3 years ago |
Dean Karn | 88976f39f6 | 3 years ago |
jtseng-godaddy | 06ec79d987 | 3 years ago |
Markus Tenghamn | 8fe074c546 | 3 years ago |
Kazuki Onishi | ec2071b383 | 3 years ago |
nesty92 | c67d01d610 | 3 years ago |
Markus Tenghamn | 19f8e61dba | 3 years ago |
Dean Karn | ce34f361cc | 3 years ago |
Metin Oğurlu | d4271985b4 | 3 years ago |
András Czigány | 42525d89ab | 3 years ago |
Xavier Vello | a67baa74f1 | 3 years ago |
Dmitriy | 14221d02a5 | 3 years ago |
Dean Karn | 6dbf61e046 | 3 years ago |
Dean Karn | 9a5bce3253 | 3 years ago |
Dean Karn | b03f1f453e | 3 years ago |
cokezhang | 61a982014e | 3 years ago |
Oleg Nikachev | 44c2696cbd | 3 years ago |
steveorourke | e40bece342 | 3 years ago |
Brian Leishman | 8cfa1e93b6 | 3 years ago |
Saed SayedAhmed | f1befad848 | 3 years ago |
Dean Karn | 65bb123677 | 3 years ago |
amir | e3e38634b1 | 3 years ago |
N/A | af8b8d1c88 | 3 years ago |
Levani | 8bfa88a462 | 3 years ago |
Dean Karn | 9104fe2461 | 3 years ago |
masafumi-i | 90ab42ba67 | 3 years ago |
Alonso Villegas | b1b32b2064 | 3 years ago |
Dean Karn | 76b917f432 | 4 years ago |
Dean Karn | 95ac68b6d7 | 4 years ago |
Dean Karn | d07eb88fb0 | 4 years ago |
ѵµσɳɠ | a53d64fc35 | 4 years ago |
Oleksii Kulikov | c2066206fe | 4 years ago |
zytell3301 | b95d43b789 | 4 years ago |
Zane DeGraffenried | 31dd62f1c9 | 4 years ago |
Dean Karn | b926bf0df9 | 4 years ago |
Josh Slate | add373fff7 | 4 years ago |
Dean Karn | 68248183b4 | 4 years ago |
Deri Herdianto | 526b0968b3 | 4 years ago |
Sergei Isaev | 2b75c46052 | 4 years ago |
frederikhors | 3c8db83c19 | 4 years ago |
Peperoncino | 5b8f3b8a0b | 4 years ago |
Torwang | 882ec0def4 | 4 years ago |
Qalifah | 0e674563ff | 4 years ago |
Michał Treter | ec1baac93d | 4 years ago |
João Francisco | 514c9dbd77 | 4 years ago |
Jake-Convictional | 9c415c4565 | 4 years ago |
Dean Karn | f6584a41c8 | 4 years ago |
Dean Karn | 3bb4866602 | 4 years ago |
Dean Karn | 456221b630 | 4 years ago |
Flávio CF Oliveira | d6b17fd90b | 4 years ago |
krhubert | f32fea830e | 4 years ago |
Brandon Lee | 704a814277 | 4 years ago |
Elias Rodrigues | 4407f4dea0 | 4 years ago |
Dean Karn | 8941cbd00e | 4 years ago |
Dean Karn | 8154ee6ca8 | 4 years ago |
Dean Karn | f0805c61ba | 4 years ago |
Dean Karn | 76981ccf75 | 4 years ago |
Dean Karn | 57b4fab34b | 4 years ago |
Dean Karn | d9e95d55e9 | 4 years ago |
Dean Karn | 2a5412a1bc | 4 years ago |
Dean Karn | 839d050f74 | 4 years ago |
Dean Karn | e6eee3ea88 | 4 years ago |
Dean Karn | b1ccceeb11 | 4 years ago |
Dean Karn | 4cd2e40256 | 4 years ago |
Dean Karn | ace513eddd | 4 years ago |
Dean Karn | 0d657b4731 | 4 years ago |
Dean Karn | 0e7e593daa | 4 years ago |
Takeshi Kaneko | f2ce6a4f92 | 4 years ago |
David Ketch | 1bf11c9299 | 4 years ago |
root | ca0533bb97 | 4 years ago |
root | 490e253792 | 4 years ago |
root | 742006d126 | 4 years ago |
hzw | 44a150f359 | 4 years ago |
nigelis | 6f81b7d8d0 | 4 years ago |
math-nao | 7dbe685a02 | 4 years ago |
Long Bui | 67c4fdf0de | 4 years ago |
Elias Rodrigues | 1cbd3081e4 | 4 years ago |
Elias Rodrigues | 33ffa4a31f | 4 years ago |
Elias Rodrigues | 55e0f418d6 | 4 years ago |
Elias Rodrigues | 04749bc4d4 | 4 years ago |
Elias Rodrigues | fc1b28803a | 4 years ago |
Elias Rodrigues | f525f0b64f | 4 years ago |
Elias Rodrigues | 48684f91aa | 4 years ago |
Elias Rodrigues | 0c71d5cc08 | 4 years ago |
Elias Rodrigues | 94470e68f3 | 4 years ago |
Elias Rodrigues | 1c4e56307b | 4 years ago |
math-nao | 44f3347f13 | 4 years ago |
Taylor | 07a4b7aa38 | 4 years ago |
Taylor | 0bfda52ce1 | 4 years ago |
Dean Karn | ea924ce89a | 5 years ago |
Dean Karn | 059510c3bf | 5 years ago |
Dean Karn | 50166a5a06 | 5 years ago |
Dean Karn | ab4e67f050 | 5 years ago |
Dean Karn | ae8ecbca8a | 5 years ago |
Dean Karn | 0ab8e0351d | 5 years ago |
Dean Karn | 7e978ff872 | 5 years ago |
Dean Karn | 957a452839 | 5 years ago |
Dean Karn | 257f202dd1 | 5 years ago |
Dean Karn | dbfcad250f | 5 years ago |
Dean Karn | 07f2314af2 | 5 years ago |
Dean Karn | a5e9e63a9a | 5 years ago |
Dean Karn | 8203121676 | 5 years ago |
Dean Karn | 175275dfea | 5 years ago |
Giuliano Scaglioni | b610155475 | 5 years ago |
Giuliano Scaglioni | 7d6236a898 | 5 years ago |
Giuliano Scaglioni | ee37674003 | 5 years ago |
Kiyan Gauss | b15bf1dead | 5 years ago |
John Bailon | 198646cbd1 | 5 years ago |
John Bailon | 7807a1f36f | 5 years ago |
amiraliucsc | c7dc8812a2 | 5 years ago |
amiraliucsc | 1611f1e72c | 5 years ago |
amiraliucsc | 18fba4ba8a | 5 years ago |
cncal | 85098861d3 | 5 years ago |
erikaleigh | 3909783b73 | 5 years ago |
Milan Divkovic | f3b347cc29 | 5 years ago |
alfonsoprado | a98911a366 | 5 years ago |
alfonsoprado | c1b73a784d | 5 years ago |
Pantelis Sampaziotis | afacb47f2b | 5 years ago |
Pantelis Sampaziotis | 9f175c7ece | 5 years ago |
Pantelis Sampaziotis | 8a19420dcf | 5 years ago |
Dean Karn | c68441b7f4 | 5 years ago |
Pantelis Sampaziotis | 912fcd16a8 | 5 years ago |
Pantelis Sampaziotis | 14f963703b | 5 years ago |
Dean Karn | b7430f8e39 | 5 years ago |
Dean Karn | 0c80f876cd | 5 years ago |
Dean Karn | 68e8e137fa | 5 years ago |
Dean Karn | 1f676c755a | 5 years ago |
Dean Karn | fa149de298 | 5 years ago |
Dean Karn | fdd54d3fc2 | 5 years ago |
Dean Karn | b541462b5a | 5 years ago |
Pantelis Sampaziotis | 2109f86248 | 5 years ago |
Pantelis Sampaziotis | 9e58bcdee1 | 5 years ago |
shenyiling | 6d2c659585 | 5 years ago |
Pantelis Sampaziotis | 5b51bff4e6 | 5 years ago |
Pantelis Sampaziotis | 581d2698d5 | 5 years ago |
Rustam | eb11afd9a8 | 5 years ago |
Ravi Terala | a1ac82a865 | 5 years ago |
Ravi Terala | 893747e5ee | 5 years ago |
Dean Karn | fb6c45823a | 5 years ago |
Dean Karn | 5b97da4cbf | 5 years ago |
Dean Karn | c2546fb355 | 5 years ago |
richi | f8a081fd83 | 5 years ago |
Shi Han NG | e73ec5f5ab | 5 years ago |
Shi Han NG | 8f604265e0 | 5 years ago |
Jean-Philippe Moal | 1effcb06a7 | 5 years ago |
Jean-Philippe Moal | 703c0b681a | 5 years ago |
Taylor | e7c70798c9 | 5 years ago |
Dean Karn | a6a294bfeb | 5 years ago |
Dean Karn | c067a8f197 | 5 years ago |
Dean Karn | 1d93fb999e | 5 years ago |
Dean Karn | 5356060ec3 | 5 years ago |
Dean Karn | 361bf41fb9 | 5 years ago |
Dean Karn | ae15ced5e1 | 5 years ago |
Nguyễn Văn Hưng | da6897303a | 5 years ago |
Streppel | 0849b1840e | 5 years ago |
Jonathan Thom | bb5fd36827 | 5 years ago |
Jonathan Thom | 685d3e21f3 | 5 years ago |
Dmitry M. Gavrovsky | d149847e8a | 5 years ago |
Dmitry M. Gavrovsky | dfc652373a | 5 years ago |
Dean Karn | 691a5f5f25 | 5 years ago |
Dean Karn | bec732e9de | 5 years ago |
Dean Karn | a346f2eea4 | 5 years ago |
Dean Karn | b11fb5f16e | 5 years ago |
Dean Karn | c0f05c7b3d | 5 years ago |
Dean Karn | fe89c745f6 | 5 years ago |
Kaelan Thijs Fouwels | 8678802a39 | 5 years ago |
Jonathan Thom | 432c17028a | 5 years ago |
sclaire-1 | 4be5d19c39 | 5 years ago |
Dean Karn | dbbe6958b3 | 5 years ago |
Dean Karn | 7e57ca0cf5 | 5 years ago |
Dean Karn | cd1bd58169 | 5 years ago |
Dean Karn | 883a9e06c8 | 5 years ago |
Dean Karn | 9593a0f77e | 5 years ago |
Dean Karn | 06f92248de | 5 years ago |
Dean Karn | 6484d9f2fb | 5 years ago |
Dean Karn | cc25246f01 | 5 years ago |
Dean Karn | 51fcc303b3 | 5 years ago |
Dean Karn | 205b733988 | 5 years ago |
Talha Ansari | 4e2a13b9bf | 5 years ago |
Talha Ansari | 2367d307c5 | 5 years ago |
baran.asaner | 80a8449877 | 5 years ago |
Dean Karn | 556b9da3c0 | 5 years ago |
Dean Karn | ab2452c1ce | 5 years ago |
Dean Karn | d6546ee64a | 5 years ago |
Tobias Sjösten | 9f6c1cdebf | 5 years ago |
Zuyang Kou | 54db112759 | 6 years ago |
Dean Karn | 884d31b8ca | 6 years ago |
Dean Karn | 56b7caa399 | 6 years ago |
Dean Karn | 727e327e57 | 6 years ago |
criherna | 38f91ec1a1 | 6 years ago |
criherna | 9dedb06449 | 6 years ago |
A Mashmooli | 8c221696bb | 6 years ago |
A Mashmooli | d89801fc29 | 6 years ago |
A Mashmooli | de92ea70b4 | 6 years ago |
A Mashmooli | 22eebe9ac5 | 6 years ago |
A Mashmooli | a9e1a9226c | 6 years ago |
A Mashmooli | 678f8d753f | 6 years ago |
A Mashmooli | 5a98da4e8c | 6 years ago |
Dean Karn | e25e66164b | 6 years ago |
A Mashmooli | 3ec10f9949 | 6 years ago |
A Mashmooli | 03bfd38cc1 | 6 years ago |
A Mashmooli | ebfddc5784 | 6 years ago |
A Mashmooli | 1e6bddb6b3 | 6 years ago |
A Mashmooli | adbd5e9b33 | 6 years ago |
Dean Karn | 46b4b1e301 | 6 years ago |
Dean Karn | c0a5f73741 | 6 years ago |
Dean Karn | 9cbbfdd691 | 6 years ago |
Dean Karn | 9980009549 | 6 years ago |
Dean Karn | 5ed5b2eeeb | 6 years ago |
Dean Karn | ce0e3d1c6d | 6 years ago |
Ben Paxton | 9099388d96 | 6 years ago |
Alex Bilbie | ab7e4092fb | 6 years ago |
Alex Bilbie | a918b74270 | 6 years ago |
Jannik C | 8a9497f4bd | 6 years ago |
Tyler Cipriani | 3945da16ee | 6 years ago |
rucas | dbd65cccbc | 6 years ago |
Andrei Avram | f2ac4efd57 | 6 years ago |
Dean Karn | b199fa0642 | 6 years ago |
Dean Karn | 1b32ac03ca | 6 years ago |
Dean Karn | e10c2c9ddb | 6 years ago |
Dean Karn | 6cdb5bb480 | 6 years ago |
Dean Karn | cf7eb8fabc | 6 years ago |
Andrei Avram | 1d286c8332 | 6 years ago |
Andrei Avram | faaace938d | 6 years ago |
Andrei Avram | 6b29637aaa | 6 years ago |
Abdallah Galal | 94ba218708 | 6 years ago |
Esslam | 891b7807f8 | 6 years ago |
Krzysztof Szafrański | fdbd8ba577 | 6 years ago |
Ramy Aboul Naga | d1d2da5f73 | 6 years ago |
Ramy Aboul Naga | cbd5cf6393 | 6 years ago |
Dean Karn | 774d09c386 | 6 years ago |
Rohan Sathe | 76020d061e | 6 years ago |
Ramy Aboul Naga | 52ea448998 | 6 years ago |
Dean Karn | cdd5c28d21 | 6 years ago |
franklin | 91d81934ab | 6 years ago |
Takeshi Akima | 9af2aa2cc3 | 6 years ago |
Dean Karn | 0277b12d53 | 6 years ago |
Dean Karn | bc745fba53 | 6 years ago |
Dean Karn | 35d48effb5 | 6 years ago |
Dean Karn | df119a3494 | 6 years ago |
Dean Karn | c7005d73ef | 6 years ago |
akm | 578166faf7 | 6 years ago |
akm | 37128de86f | 6 years ago |
Leonardo Di Donato | 2bb313f957 | 6 years ago |
Leonardo Di Donato | 0482874b86 | 6 years ago |
Leonardo Di Donato | c5423e4116 | 6 years ago |
Anderson Guilherme Porto | 20357ae332 | 6 years ago |
Dean Karn | 6079fcc186 | 6 years ago |
満行芳樹 | aaf2c06dbe | 6 years ago |
Sam Wang | df107f0184 | 6 years ago |
Dean Karn | 1fa3c8d633 | 6 years ago |
Dean Karn | 9c187c39d8 | 6 years ago |
Dean Karn | 1730262625 | 6 years ago |
andreas | 8ed00e2e12 | 6 years ago |
andreas | 9eeca29136 | 6 years ago |
Sulthon Zainul Habib | 38f9a73e57 | 6 years ago |
andreas | 5b14fca011 | 6 years ago |
Dean Karn | 3be3142400 | 6 years ago |
Dean Karn | 9f802bbd9b | 6 years ago |
kanozec | 532cde1085 | 6 years ago |
Duncan Holm | 29b73202fe | 6 years ago |
Dean Karn | f8af4b15db | 6 years ago |
Alexander Shepelin | 868936b862 | 6 years ago |
Dean Karn | 16a72ff827 | 6 years ago |
sakura1116vg | 9c31c8d387 | 6 years ago |
Dean Karn | e69e9a28bb | 6 years ago |
Dean Karn | 4c0b0c3d27 | 6 years ago |
wessel.linden@gmail.com | 1ae2003487 | 6 years ago |
Dean Karn | ab2a8a9908 | 6 years ago |
Dean Karn | e4e19c02df | 6 years ago |
foolin | a2ec0a8018 | 6 years ago |
Dean Karn | e055f4eb7f | 6 years ago |
Dean Karn | 29f025ab2f | 6 years ago |
Damir Vandic | bdae516532 | 6 years ago |
Dean Karn | d942191d51 | 6 years ago |
Dean Karn | 5d3224279f | 6 years ago |
foolin | 11caf00975 | 6 years ago |
Foolin | d1a82a6cdc | 6 years ago |
Foolin | 801b2c40bc | 6 years ago |
Foolin | 83b055d6df | 6 years ago |
Dean Karn | ce9336f6e2 | 7 years ago |
Dean Karn | c52a27f737 | 7 years ago |
heatwole | 0a9b75fbfd | 7 years ago |
Dean Karn | 9d03e2526a | 7 years ago |
Noi Bar | ea9cb424fd | 7 years ago |
Dean Karn | fb72538343 | 7 years ago |
Dean Karn | 71510749b8 | 7 years ago |
Noi Bar | f2fdb60d7d | 7 years ago |
Dean Karn | f28cb45dc0 | 7 years ago |
Dean Karn | 3e51773f21 | 7 years ago |
Tengis B | 8d3aa5bde2 | 7 years ago |
Dean Karn | ffe836d736 | 7 years ago |
Dean Karn | 801c8790f3 | 7 years ago |
Dean Karn | 9848c01055 | 7 years ago |
Joachim Adomeit | 379fb67047 | 7 years ago |
Dean Karn | ee0bbdea51 | 7 years ago |
Dean Karn | 54da7fa48f | 7 years ago |
Dean Karn | b297167b88 | 7 years ago |
Dean Karn | f459c64611 | 7 years ago |
James Service | d978a4b421 | 7 years ago |
James Service | fc5fbce706 | 7 years ago |
James Service | 8ae3903dd3 | 7 years ago |
Ashton Kinslow | 9f62099643 | 7 years ago |
Dean Karn | 14984d9132 | 7 years ago |
Dean Karn | b5512bc1ff | 7 years ago |
josh | 073682ea75 | 7 years ago |
josh | ce6284a6fc | 7 years ago |
josh | 6deddf27eb | 7 years ago |
josh | 3df85bdcfc | 7 years ago |
josh | 60417282a4 | 7 years ago |
josh | 36d83b0b83 | 7 years ago |
Dean Karn | ff1ee42e83 | 7 years ago |
Dean Karn | d3984c2e0b | 7 years ago |
Dean Karn | 2a8a333913 | 7 years ago |
Dean Karn | 4894e4ca6c | 7 years ago |
josh | ba5836f763 | 7 years ago |
Kyriakos Georgiou | 030800a855 | 7 years ago |
Dean Karn | 8ce234ff02 | 7 years ago |
Dean Karn | b226c5e0d7 | 7 years ago |
Afranio Martins | 5186bfe8b5 | 7 years ago |
Dean Karn | 1b8c8e19cd | 7 years ago |
Frederic Delbos | 4dbd40f597 | 7 years ago |
Dean Karn | 150fe5b6a4 | 7 years ago |
Dean Karn | 34ccc97914 | 7 years ago |
Russ Egan | 2e9adc3329 | 7 years ago |
Russ Egan | 15217303f9 | 7 years ago |
Dean Karn | 535f85221e | 7 years ago |
Dean Karn | 5e036656b8 | 7 years ago |
Dean Karn | 3620d3c069 | 7 years ago |
Dean Karn | 36cd0d5b69 | 7 years ago |
Geoff Baskwill | 866bd2a946 | 7 years ago |
Dean Karn | 48a433ba4b | 7 years ago |
Dean Karn | e00f5e092a | 7 years ago |
Dean Karn | b962f3d7d5 | 7 years ago |
Dean Karn | 230db62e07 | 7 years ago |
Dean Karn | b1f51f36f1 | 7 years ago |
Dean Karn | 61caf9d303 | 7 years ago |
Dean Karn | 1304298bf1 | 7 years ago |
Dean Karn | 11e5ebe8a1 | 7 years ago |
Dean Karn | 34b84953ff | 7 years ago |
Dean Karn | 11a1fab51d | 7 years ago |
Dean Karn | 946d444376 | 7 years ago |
Dean Karn | a021b2ec9a | 7 years ago |
Dean Karn | f16354ec03 | 7 years ago |
Dean Karn | e3037695c7 | 7 years ago |
Aaron Lehmann | 770163b1e1 | 7 years ago |
Dean Karn | 0d09605a05 | 7 years ago |
Dean Karn | 0b5dc7605b | 7 years ago |
Dean Karn | 893aecca31 | 7 years ago |
pigi72333 | 17c6ef0e87 | 7 years ago |
Dean Karn | 65480b6f6c | 7 years ago |
Lucas Mundim | 8e400db116 | 7 years ago |
Dean Karn | 5c4193d98e | 7 years ago |
Dean Karn | d529ee1b0f | 7 years ago |
Bruno Lorenz | dbd50b343f | 7 years ago |
Bruno Lorenz | 1669b6e0ee | 7 years ago |
Bruno Lorenz | 08796346a0 | 7 years ago |
Dean Karn | 44d9acf0a8 | 7 years ago |
Dean Karn | 0f6f568263 | 7 years ago |
Dean Karn | fb68f39656 | 8 years ago |
Dean Karn | 27158c7a84 | 8 years ago |
Dean Karn | 6d8c18553e | 8 years ago |
Dean Karn | 755afb9dde | 8 years ago |
Francois Lebel | 7a2859f38d | 8 years ago |
Dean Karn | 4bd1935852 | 8 years ago |
Dean Karn | b250b44763 | 8 years ago |
Dean Karn | 691ea55063 | 8 years ago |
Dean Karn | 0cc1e78abb | 8 years ago |
Ellison Leão | 7cd869b083 | 8 years ago |
Dean Karn | fb258d3590 | 8 years ago |
Osamu TONOMORI | cf230a98d7 | 8 years ago |
Dean Karn | 077c3830f3 | 8 years ago |
Dean Karn | 49fccadad1 | 8 years ago |
Dean Karn | 941ce2cabc | 8 years ago |
Dean Karn | 4d76b0dd81 | 8 years ago |
Dean Karn | 597f93b316 | 8 years ago |
Dean Karn | 4e43fa1562 | 8 years ago |
Dean Karn | 493dfb6209 | 8 years ago |
Dean Karn | 506cc5da56 | 8 years ago |
Dean Karn | 0c0ae405d3 | 8 years ago |
Dean Karn | 335c8e2fac | 8 years ago |
Jawher Moussa | 73e8e76de2 | 8 years ago |
Dean Karn | 23e84d2f88 | 8 years ago |
Dean Karn | 678f8cf9a3 | 8 years ago |
Dean Karn | cddc415625 | 8 years ago |
Dean Karn | 42a0d6df3b | 8 years ago |
Dean Karn | 7c2b5d8471 | 8 years ago |
Dean Karn | 4b3eedc379 | 8 years ago |
Dean Karn | 110c8638eb | 8 years ago |
Dean Karn | 0e70fdfc72 | 8 years ago |
Dean Karn | a7ca4a1d32 | 8 years ago |
Dean Karn | 532878b008 | 8 years ago |
Dean Karn | 6f98212623 | 8 years ago |
Dean Karn | 0af0043f29 | 8 years ago |
Dean Karn | a7cc53a707 | 8 years ago |
Dean Karn | 9ba3297c49 | 8 years ago |
Dean Karn | 1cbfa0bbff | 8 years ago |
joeybloggs | b0883e6ed8 | 8 years ago |
Dean Karn | 852e5ff9f9 | 8 years ago |
joeybloggs | 2de56ed26a | 8 years ago |
joeybloggs | 3e196d49c6 | 8 years ago |
joeybloggs | b2c8f66e7b | 8 years ago |
joeybloggs | ea09db9292 | 8 years ago |
joeybloggs | 1714ba2b67 | 8 years ago |
joeybloggs | 6765805f88 | 8 years ago |
joeybloggs | 27b607d6ad | 8 years ago |
joeybloggs | 01925e342a | 8 years ago |
joeybloggs | ecad6333b1 | 8 years ago |
joeybloggs | dcdba454d7 | 8 years ago |
joeybloggs | d9bfef9fe0 | 8 years ago |
joeybloggs | 8d0fd80a80 | 8 years ago |
joeybloggs | a8f7aaba72 | 8 years ago |
joeybloggs | f581a2d517 | 8 years ago |
joeybloggs | 98dee40973 | 8 years ago |
joeybloggs | 560bff6526 | 8 years ago |
joeybloggs | 8c60a612c5 | 8 years ago |
joeybloggs | 2fe87f7a8d | 8 years ago |
joeybloggs | 5fedd8c08a | 8 years ago |
joeybloggs | 5d28ac67f7 | 8 years ago |
joeybloggs | 1ff58be284 | 8 years ago |
joeybloggs | 3bf69e2bbd | 8 years ago |
joeybloggs | 7e731afde9 | 8 years ago |
joeybloggs | e0e1af6a61 | 8 years ago |
Dean Karn | 598aac293f | 8 years ago |
joeybloggs | 5f57d2222a | 8 years ago |
joeybloggs | 77f59a0ea0 | 8 years ago |
joeybloggs | 1d3a3d281b | 8 years ago |
joeybloggs | 89d5a94084 | 8 years ago |
joeybloggs | 80301d1184 | 8 years ago |
joeybloggs | 49d9b2c35e | 8 years ago |
joeybloggs | 99a0f5e141 | 8 years ago |
joeybloggs | 7a080ada5b | 8 years ago |
Dean Karn | 393130c3f4 | 8 years ago |
joeybloggs | 3ef55a89aa | 8 years ago |
joeybloggs | 43f7b7d61a | 8 years ago |
joeybloggs | 05d6aece82 | 8 years ago |
joeybloggs | 4ce4d1cd71 | 8 years ago |
joeybloggs | 330b12dacd | 8 years ago |
joeybloggs | 210684a828 | 8 years ago |
joeybloggs | c0a414dc9e | 8 years ago |
joeybloggs | 5c8ad6a1a9 | 9 years ago |
joeybloggs | cdfcf16a86 | 9 years ago |
Dean Karn | 25f1823069 | 9 years ago |
Kenneth Kouot | 719d0b12ee | 9 years ago |
Kenneth Kouot | 3499e730cb | 9 years ago |
joeybloggs | 014792cf3e | 9 years ago |
joeybloggs | e7749ea250 | 9 years ago |
joeybloggs | 93bb347253 | 9 years ago |
Dean Karn | 1214d3629c | 9 years ago |
Dean Karn | bd356b6899 | 9 years ago |
Kevin Seidel | 851787be1b | 9 years ago |
joeybloggs | f38559b489 | 9 years ago |
Dean Karn | 4c79e69823 | 9 years ago |
joeybloggs | bf5ac690d6 | 9 years ago |
joeybloggs | 6851add4e4 | 9 years ago |
joeybloggs | 4cb9152af0 | 9 years ago |
joeybloggs | faf40fd62f | 9 years ago |
Dean Karn | 73aaa89512 | 9 years ago |
joeybloggs | 7b758151c6 | 9 years ago |
Hubert Krauze | 3eaf857419 | 9 years ago |
Hubert Krauze | ee0ce7d37e | 9 years ago |
Hubert Krauze | 312ba49f28 | 9 years ago |
Hubert Krauze | def24ae611 | 9 years ago |
Hubert Krauze | 5a99cf6052 | 9 years ago |
joeybloggs | c193cecd12 | 9 years ago |
joeybloggs | 64b7e2bb79 | 9 years ago |
joeybloggs | 50ada8d03a | 9 years ago |
Dean Karn | d370e28d44 | 9 years ago |
Aaron Greenlee | 0b51ee1e8e | 9 years ago |
Aaron Greenlee | 71d9b9e91c | 9 years ago |
Aaron Greenlee | 24ea3a17b5 | 9 years ago |
Dean Karn | e8d470cd7a | 9 years ago |
Dean Karn | b737e38edb | 9 years ago |
joeybloggs | 0862513fbf | 9 years ago |
joeybloggs | 0b533f264c | 9 years ago |
joeybloggs | afbcf59553 | 9 years ago |
Dean Karn | bc50625289 | 9 years ago |
Dean Karn | e7cce24a67 | 9 years ago |
Anthony Olurin | c4d5999ec0 | 9 years ago |
Dean Karn | 43f534e655 | 9 years ago |
Dean Karn | 8040a52f21 | 9 years ago |
joeybloggs | 934bef0ce5 | 9 years ago |
Dean Karn | 0794474f60 | 9 years ago |
Dean Karn | 589c2ad113 | 9 years ago |
joeybloggs | e019c28542 | 9 years ago |
joeybloggs | 94182a2199 | 9 years ago |
Dean Karn | 638ea8a3f8 | 9 years ago |
Dean Karn | d5987d5437 | 9 years ago |
joeybloggs | b0bd08d7c8 | 9 years ago |
Dean Karn | ec28e2da37 | 9 years ago |
Dean Karn | 47c3cabf25 | 9 years ago |
joeybloggs | d451d57023 | 9 years ago |
Dean Karn | d776d3eb2e | 9 years ago |
Dean Karn | ba623db026 | 9 years ago |
joeybloggs | 41828a2d17 | 9 years ago |
joeybloggs | cab69bdd13 | 9 years ago |
Dean Karn | 82faf6f72a | 9 years ago |
Dean Karn | aea222d51c | 9 years ago |
joeybloggs | 24c1c6819f | 9 years ago |
Dean Karn | 27557e4813 | 9 years ago |
Dean Karn | 5ad5c12aab | 9 years ago |
joeybloggs | 59859969c6 | 9 years ago |
Dean Karn | c5efdc9576 | 9 years ago |
Dean Karn | 6268452877 | 9 years ago |
joeybloggs | 29403404e4 | 9 years ago |
Dean Karn | 2ecdb677b3 | 9 years ago |
Dean Karn | 885fd6cb97 | 9 years ago |
joeybloggs | a48387a078 | 9 years ago |
joeybloggs | f1acffdfe0 | 9 years ago |
Dean Karn | 5f64c229a4 | 9 years ago |
Dean Karn | 11b132ba0b | 9 years ago |
Dean Karn | a21885483f | 9 years ago |
Dean Karn | 9a3b21ded0 | 9 years ago |
joeybloggs | 1570c9b6b3 | 9 years ago |
Dean Karn | d5305abfab | 9 years ago |
Dean Karn | 377e5e06a1 | 9 years ago |
joeybloggs | fc5d9f3ae0 | 9 years ago |
Dean Karn | 247a19d4b0 | 9 years ago |
Dean Karn | 17084684e6 | 9 years ago |
Hubert | d015334e09 | 9 years ago |
Hubert | 9ffc753204 | 9 years ago |
Dean Karn | ea31d3ec23 | 9 years ago |
Fábio Gomes | 28b6964c53 | 9 years ago |
Dean Karn | 7bfad40793 | 9 years ago |
Dean Karn | e82c80a530 | 9 years ago |
joeybloggs | 46f4476335 | 9 years ago |
joeybloggs | 3cef97a452 | 9 years ago |
Dean Karn | 344bcd6e10 | 9 years ago |
İlker Göktuğ Öztürk | 5bc0ff91f8 | 9 years ago |
Dean Karn | 92ddaeb7d8 | 9 years ago |
Dean Karn | 8818fdcf0b | 9 years ago |
joeybloggs | c8fb9a5e7c | 9 years ago |
Dean Karn | 5b7705b83f | 9 years ago |
joeybloggs | 36c0f0aa99 | 9 years ago |
Dean Karn | 8324129b02 | 9 years ago |
Dean Karn | d173a35b5c | 9 years ago |
joeybloggs | 95e8b47837 | 9 years ago |
joeybloggs | 830d270923 | 9 years ago |
Dean Karn | ec1066576d | 9 years ago |
Dean Karn | 1a791b52ba | 9 years ago |
Dean Karn | 0f4bcfc83f | 9 years ago |
joeybloggs | eab946fcd9 | 9 years ago |
joeybloggs | d5f9115ad5 | 9 years ago |
Dean Karn | 40bd6a0bc0 | 9 years ago |
joeybloggs | aa72515d75 | 9 years ago |
joeybloggs | 8119861695 | 9 years ago |
joeybloggs | 9e4314f9ab | 9 years ago |
joeybloggs | b366564cbe | 9 years ago |
joeybloggs | e8133a0b33 | 9 years ago |
Dean Karn | e66bd708c4 | 9 years ago |
joeybloggs | 14df416126 | 9 years ago |
Dean Karn | 0650f73d40 | 9 years ago |
Joel Williams | 715aa553c8 | 9 years ago |
joeybloggs | 22a5f70a0e | 9 years ago |
joeybloggs | d792c5a578 | 9 years ago |
joeybloggs | 19b2f07d98 | 9 years ago |
joeybloggs | b2d8b4186c | 9 years ago |
joeybloggs | 9990e055a3 | 9 years ago |
joeybloggs | 0b51279b05 | 9 years ago |
joeybloggs | 70cb087d5a | 9 years ago |
joeybloggs | 10cf645b91 | 9 years ago |
joeybloggs | 9988ba3f45 | 9 years ago |
joeybloggs | 4807bf93bb | 9 years ago |
joeybloggs | c293315337 | 9 years ago |
joeybloggs | b213226b01 | 9 years ago |
joeybloggs | b4563c2cf6 | 9 years ago |
joeybloggs | a964f5384a | 9 years ago |
joeybloggs | 407aac458f | 9 years ago |
joeybloggs | 2cda50fb41 | 9 years ago |
Dean Karn | f6ff3d4da3 | 9 years ago |
Dean Karn | ca7facef9c | 9 years ago |
joeybloggs | 3191556e30 | 9 years ago |
Dean Karn | 9a7e605915 | 9 years ago |
Dean Karn | d5462d5b41 | 9 years ago |
Dean Karn | 8146ec40c7 | 9 years ago |
joeybloggs | 77751ca042 | 9 years ago |
joeybloggs | 4ab8352362 | 9 years ago |
Dean Karn | 72a602000a | 9 years ago |
Dean Karn | 95213db264 | 9 years ago |
Dean Karn | d423756cc0 | 9 years ago |
joeybloggs | ce06c47267 | 9 years ago |
joeybloggs | 43d7f25cfb | 9 years ago |
joeybloggs | 55f9e44ce5 | 9 years ago |
joeybloggs | 15fdf82c30 | 9 years ago |
joeybloggs | 3f4f84c358 | 9 years ago |
Dean Karn | 19d8904f2c | 9 years ago |
joeybloggs | 14b90946b3 | 9 years ago |
joeybloggs | d7b348e4b3 | 9 years ago |
Dean Karn | b5317c5c5c | 9 years ago |
joeybloggs | 7757a227ed | 9 years ago |
joeybloggs | 883731a774 | 9 years ago |
joeybloggs | 4f46e02133 | 9 years ago |
joeybloggs | 387cfe5aa9 | 9 years ago |
joeybloggs | 656ae32e8b | 9 years ago |
joeybloggs | 4a8a489366 | 9 years ago |
Dean Karn | 305c50fb58 | 9 years ago |
Dean Karn | 6df82fdf49 | 9 years ago |
Dean Karn | 8a9ed1f107 | 9 years ago |
joeybloggs | 844f5f46f7 | 9 years ago |
joeybloggs | 8ae139a445 | 9 years ago |
joeybloggs | 3697be93be | 9 years ago |
joeybloggs | 8ff687aae4 | 9 years ago |
joeybloggs | 1fbc384272 | 9 years ago |
joeybloggs | 327aa2e826 | 9 years ago |
joeybloggs | cd50c5e085 | 9 years ago |
joeybloggs | 3a0791591a | 9 years ago |
joeybloggs | 4cbf0659ce | 9 years ago |
joeybloggs | 5989727cf7 | 9 years ago |
joeybloggs | 8aea478060 | 9 years ago |
joeybloggs | 2fe52ca08f | 9 years ago |
joeybloggs | d19088f865 | 9 years ago |
joeybloggs | 81e29d3724 | 9 years ago |
joeybloggs | 2ea9043764 | 9 years ago |
joeybloggs | 3ab458c80c | 9 years ago |
Dean Karn | c62ee7ccdf | 9 years ago |
Dean Karn | 494e1360ec | 9 years ago |
joeybloggs | 50f0798342 | 9 years ago |
Dean Karn | 0cd5e89c38 | 9 years ago |
Dean Karn | 3f5b785707 | 9 years ago |
joeybloggs | 7e97fcf2c4 | 9 years ago |
Dean Karn | f8fd45620a | 9 years ago |
Dean Karn | a13509df8f | 9 years ago |
Dean Karn | 442b210016 | 9 years ago |
joeybloggs | d2ea21ad15 | 9 years ago |
Kevin Harrington | 7c844893e1 | 9 years ago |
joeybloggs | 048d7b8100 | 9 years ago |
Dean Karn | 32910f84c4 | 9 years ago |
joeybloggs | 6a8ed5612a | 9 years ago |
Dean Karn | 790122c21c | 9 years ago |
Dean Karn | d802346da4 | 9 years ago |
Dean Karn | a05046f9e7 | 9 years ago |
joeybloggs | d363ed316c | 9 years ago |
Dean Karn | 55e8c8d9ca | 9 years ago |
Dean Karn | a7e8a12f07 | 9 years ago |
joeybloggs | 143b21eba1 | 9 years ago |
joeybloggs | bd16331fc0 | 9 years ago |
Dean Karn | c0001173ee | 9 years ago |
Dean Karn | a56318009b | 9 years ago |
joeybloggs | e078205c78 | 9 years ago |
Dean Karn | 54927e92d9 | 9 years ago |
Dean Karn | f4625158e0 | 9 years ago |
joeybloggs | ea0db1fa47 | 9 years ago |
Dean Karn | c59a51f3e9 | 9 years ago |
joeybloggs | 201c892979 | 9 years ago |
Dean Karn | b9cdaa4346 | 9 years ago |
Dean Karn | 781f596065 | 9 years ago |
joeybloggs | aef21d4d30 | 9 years ago |
joeybloggs | a5d0ef37b8 | 9 years ago |
Dean Karn | a87651c07b | 9 years ago |
Dean Karn | fd0f7cd349 | 9 years ago |
Dean Karn | 06ad2498ab | 9 years ago |
joeybloggs | cdc48b4f90 | 9 years ago |
joeybloggs | 506e57e4d7 | 9 years ago |
Dean Karn | b009996c4a | 9 years ago |
Dean Karn | d078eb5498 | 9 years ago |
Dean Karn | 9e60f7d11b | 9 years ago |
joeybloggs | 2baa4bd353 | 9 years ago |
Dean Karn | 347979cec7 | 9 years ago |
Dean Karn | 2a2b70052e | 9 years ago |
Dean Karn | ae135ef613 | 9 years ago |
Dean Karn | fbc15ff5c6 | 9 years ago |
joeybloggs | 41b4a43989 | 9 years ago |
joeybloggs | 933fe0b7a9 | 9 years ago |
joeybloggs | e005b06f11 | 10 years ago |
joeybloggs | e2a5b9881e | 10 years ago |
joeybloggs | 4bdd703409 | 10 years ago |
joeybloggs | 07f2263b41 | 10 years ago |
joeybloggs | 7f4b49c751 | 10 years ago |
joeybloggs | 4ce39526f6 | 10 years ago |
joeybloggs | 24d46304a8 | 10 years ago |
joeybloggs | 88cc19b9e1 | 10 years ago |
joeybloggs | 4d2ffbedfc | 10 years ago |
joeybloggs | 019c5fc4ac | 10 years ago |
joeybloggs | 68ba87af24 | 10 years ago |
joeybloggs | 7af3fb7c1f | 10 years ago |
joeybloggs | 953cc993e6 | 10 years ago |
Dean Karn | ac33a23e6e | 10 years ago |
Dean Karn | 8a9bd75ae8 | 10 years ago |
joeybloggs | 89e9d9731d | 10 years ago |
joeybloggs | b52f154023 | 10 years ago |
Dean Karn | 314b33a481 | 10 years ago |
joeybloggs | 9596b89a26 | 10 years ago |
zhing | 3bece518fa | 10 years ago |
zhing | 0fa8dd2a3e | 10 years ago |
joeybloggs | e42d7b683a | 10 years ago |
joeybloggs | c62550c414 | 10 years ago |
Dean Karn | ed304c7fdf | 10 years ago |
Dean Karn | 06aac46c91 | 10 years ago |
Dean Karn | 988489de15 | 10 years ago |
joeybloggs | 9d2b8ee9d4 | 10 years ago |
joeybloggs | e1fd32247f | 10 years ago |
Dean Karn | e02a29b19b | 10 years ago |
The Gitter Badger | c4ae288afd | 10 years ago |
Dean Karn | 7422dd4828 | 10 years ago |
Dean Karn | 6ae2952f55 | 10 years ago |
Dean Karn | d2748d5ae5 | 10 years ago |
Dean Karn | 28b71ba8ae | 10 years ago |
joeybloggs | 9d4c0ec302 | 10 years ago |
joeybloggs | 302c3cffdd | 10 years ago |
joeybloggs | 562e77833a | 10 years ago |
Dean Karn | 31fb6bb006 | 10 years ago |
Dean Karn | b9105b5bf7 | 10 years ago |
Dean Karn | e5ebe76ccf | 10 years ago |
joeybloggs | 46b655a956 | 10 years ago |
joeybloggs | c4203fff25 | 10 years ago |
joeybloggs | 89a5909004 | 10 years ago |
Dean Karn | f88ea46a9a | 10 years ago |
Dean Karn | 0e7326e6a7 | 10 years ago |
Dean Karn | 82abe38795 | 10 years ago |
Dean Karn | 26333a65c1 | 10 years ago |
Dean Karn | 5ca3cffc8c | 10 years ago |
Dean Karn | d8e0c4d936 | 10 years ago |
Dean Karn | 4f5ff0f3b4 | 10 years ago |
joeybloggs | 92bd6b335a | 10 years ago |
joeybloggs | f604b6cc96 | 10 years ago |
joeybloggs | 4d57165562 | 10 years ago |
joeybloggs | 7d55bfddde | 10 years ago |
Dean Karn | d627af88ac | 10 years ago |
Dean Karn | f6358a9d49 | 10 years ago |
joeybloggs | c7ff296dca | 10 years ago |
Dean Karn | 7ce6ffcb4d | 10 years ago |
Dean Karn | 740b7d0daa | 10 years ago |
Dean Karn | 4574ba54c6 | 10 years ago |
joeybloggs | 22aaa55c7c | 10 years ago |
joeybloggs | 200a5b4aad | 10 years ago |
joeybloggs | 8bf793acde | 10 years ago |
joeybloggs | 14f176e8ac | 10 years ago |
joeybloggs | 98f4165fae | 10 years ago |
joeybloggs | a0f6d14ada | 10 years ago |
joeybloggs | 689d3e9989 | 10 years ago |
joeybloggs | 1ba858eec1 | 10 years ago |
joeybloggs | 6eded1f817 | 10 years ago |
joeybloggs | d019d02290 | 10 years ago |
joeybloggs | 4afdc19aef | 10 years ago |
joeybloggs | a3cf2f5cf3 | 10 years ago |
Dean Karn | 27a1d3f158 | 10 years ago |
Dean Karn | 3e4207bccb | 10 years ago |
joeybloggs | e0e86490bf | 10 years ago |
joeybloggs | e0bfa17b22 | 10 years ago |
Dean Karn | c06d47f593 | 10 years ago |
Dean Karn | 64eb07fa30 | 10 years ago |
joeybloggs | 63a3b7e6ad | 10 years ago |
joeybloggs | 35aff710e4 | 10 years ago |
joeybloggs | 7aa70841bc | 10 years ago |
joeybloggs | 20d9b7909f | 10 years ago |
joeybloggs | 05e0fe1f85 | 10 years ago |
joeybloggs | 5db5165e2c | 10 years ago |
joeybloggs | 9ff11ae808 | 10 years ago |
Dean Karn | 049d448603 | 10 years ago |
Dean Karn | df95f9de27 | 10 years ago |
Dean Karn | be66dfe125 | 10 years ago |
joeybloggs | f4837a073b | 10 years ago |
Dean Karn | ecfab4f37a | 10 years ago |
Dean Karn | ac10117172 | 10 years ago |
joeybloggs | fcbf6b65e4 | 10 years ago |
joeybloggs | 678d778cba | 10 years ago |
joeybloggs | 0fbc3228e8 | 10 years ago |
Dean Karn | 4cf1b67b2d | 10 years ago |
Dean Karn | c6a510f8a9 | 10 years ago |
Dean Karn | d40121962a | 10 years ago |
joeybloggs | 793099be40 | 10 years ago |
Dean Karn | 6ae296cb93 | 10 years ago |
Dean Karn | 76bccce51f | 10 years ago |
Dean Karn | 8461815c10 | 10 years ago |
Dean Karn | 3d15a126d3 | 10 years ago |
joeybloggs | 1fda4930f6 | 10 years ago |
joeybloggs | aa275c658d | 10 years ago |
joeybloggs | 39656b5186 | 10 years ago |
joeybloggs | 98ee4c3a5d | 10 years ago |
Dean Karn | c085ab22ea | 10 years ago |
Nikolay Kirsh | c09c7a1231 | 10 years ago |
joeybloggs | 56b4ce1811 | 10 years ago |
joeybloggs | 81ce302975 | 10 years ago |
joeybloggs | ad39bb92dd | 10 years ago |
joeybloggs | 6ffa5d1455 | 10 years ago |
joeybloggs | 8c2248a5ce | 10 years ago |
joeybloggs | 0c5fbee316 | 10 years ago |
joeybloggs | e4f2ff67bd | 10 years ago |
joeybloggs | 22d031deb0 | 10 years ago |
Dean Karn | 6fe54bc1d3 | 10 years ago |
Dean Karn | 1d61bf3148 | 10 years ago |
Dean Karn | 61e4429b20 | 10 years ago |
joeybloggs | fbb3befecb | 10 years ago |
joeybloggs | beaa9adf31 | 10 years ago |
Dean Karn | 8df4eb813b | 10 years ago |
Dean Karn | 479d3f0fd9 | 10 years ago |
Dean Karn | 756455cce5 | 10 years ago |
joeybloggs | e5c73961c7 | 10 years ago |
joeybloggs | ae2d0646af | 10 years ago |
joeybloggs | e0b68a7520 | 10 years ago |
Dean Karn | 2be1659b5b | 10 years ago |
Dean Karn | 07cbdd2e6d | 10 years ago |
Dean Karn | 5ab4925073 | 10 years ago |
joeybloggs | 3dcc019b64 | 10 years ago |
joeybloggs | 9d18657e1f | 10 years ago |
joeybloggs | fd059fe2f1 | 10 years ago |
Dean Karn | 40c38f9931 | 10 years ago |
Dean Karn | 63658537be | 10 years ago |
Dean Karn | d780b124a9 | 10 years ago |
Dean Karn | ee35a115e9 | 10 years ago |
joeybloggs | f7f779fb31 | 10 years ago |
joeybloggs | 23c3fa6b63 | 10 years ago |
Dean Karn | 74d0e52ab3 | 10 years ago |
Dean Karn | 73747bdf83 | 10 years ago |
Dean Karn | 1a0a2f52c4 | 10 years ago |
joeybloggs | b891b1cf3c | 10 years ago |
Dean Karn | 98f3221631 | 10 years ago |
Dean Karn | 4e9461558c | 10 years ago |
Dean Karn | fa8e0664b2 | 10 years ago |
Dean Karn | 765fb71956 | 10 years ago |
Dean Karn | e530eb5470 | 10 years ago |
Dean Karn | 1d008b4ad2 | 10 years ago |
Dean Karn | 4c73ffba66 | 10 years ago |
Dean Karn | d400cda52e | 10 years ago |
Anthony Olurin | 700e5f4b46 | 10 years ago |
Dean Karn | 829b13775f | 10 years ago |
Dean Karn | 04b0ff368d | 10 years ago |
Dean Karn | 42419864c0 | 10 years ago |
Dean Karn | d474ce1ce6 | 10 years ago |
Dean Karn | 9d1ffaeb87 | 10 years ago |
Dean Karn | 7ac98be692 | 10 years ago |
@ -0,0 +1 @@ |
||||
* @go-playground/validator-maintainers |
@ -0,0 +1,9 @@ |
||||
# Contribution Guidelines |
||||
|
||||
## Quality Standard |
||||
|
||||
To ensure the continued stability of this package, tests are required that cover the change in order for a pull request to be merged. |
||||
|
||||
## Reporting issues |
||||
|
||||
Please open an issue or join the gitter chat [![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) for any issues, questions or possible enhancements to the package. |
@ -0,0 +1,16 @@ |
||||
- [ ] I have looked at the documentation [here](https://pkg.go.dev/github.com/go-playground/validator/v10#section-documentation) first? |
||||
- [ ] I have looked at the examples provided that may showcase my question [here](/_examples)? |
||||
|
||||
### Package version eg. v9, v10: |
||||
|
||||
|
||||
|
||||
### Issue, Question or Enhancement: |
||||
|
||||
|
||||
|
||||
### Code sample, to showcase or reproduce: |
||||
|
||||
```go |
||||
|
||||
``` |
@ -0,0 +1,7 @@ |
||||
## Fixes Or Enhances |
||||
|
||||
|
||||
**Make sure that you've checked the boxes below before you submit PR:** |
||||
- [ ] Tests exist or have been written that cover this particular change. |
||||
|
||||
@go-playground/validator-maintainers |
@ -0,0 +1,51 @@ |
||||
on: |
||||
push: |
||||
branches: |
||||
- master |
||||
pull_request: |
||||
name: Test |
||||
jobs: |
||||
test: |
||||
strategy: |
||||
matrix: |
||||
go-version: [1.19.x] |
||||
os: [ubuntu-latest, macos-latest, windows-latest] |
||||
runs-on: ${{ matrix.os }} |
||||
steps: |
||||
- name: Install Go |
||||
uses: actions/setup-go@v3 |
||||
with: |
||||
go-version: ${{ matrix.go-version }} |
||||
|
||||
- name: Checkout code |
||||
uses: actions/checkout@v3 |
||||
|
||||
- name: Restore Cache |
||||
uses: actions/cache@v3 |
||||
with: |
||||
path: ~/go/pkg/mod |
||||
key: ${{ runner.os }}-v1-go-${{ hashFiles('**/go.sum') }} |
||||
restore-keys: | |
||||
${{ runner.os }}-v1-go- |
||||
|
||||
- name: Test |
||||
run: go test -race -covermode=atomic -coverprofile="profile.cov" ./... |
||||
|
||||
- name: Send Coverage |
||||
if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.19.x' |
||||
uses: shogo82148/actions-goveralls@v1 |
||||
with: |
||||
path-to-profile: profile.cov |
||||
|
||||
golangci: |
||||
name: lint |
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- uses: actions/setup-go@v3 |
||||
with: |
||||
go-version: 1.19.x |
||||
- uses: actions/checkout@v3 |
||||
- name: golangci-lint |
||||
uses: golangci/golangci-lint-action@v3 |
||||
with: |
||||
version: v1.50.1 |
@ -1,16 +0,0 @@ |
||||
language: go |
||||
|
||||
notificaitons: |
||||
email: |
||||
recipients: bluesuncorp01@gmail.com |
||||
on_success: change |
||||
on_failure: always |
||||
|
||||
before_script: |
||||
- go get gopkg.in/check.v1 |
||||
|
||||
go: |
||||
- 1.2 |
||||
- 1.3 |
||||
- 1.4 |
||||
- tip |
@ -0,0 +1,16 @@ |
||||
## Maintainers Guide |
||||
|
||||
### Semantic Versioning |
||||
Semantic versioning as defined [here](https://semver.org) must be strictly adhered to. |
||||
|
||||
### External Dependencies |
||||
Any new external dependencies MUST: |
||||
- Have a compatible LICENSE present. |
||||
- Be actively maintained. |
||||
- Be approved by @go-playground/admins |
||||
|
||||
### PR Merge Requirements |
||||
- Up-to-date branch. |
||||
- Passing tests and linting. |
||||
- CODEOWNERS approval. |
||||
- Tests that cover both the Happy and Unhappy paths. |
@ -0,0 +1,18 @@ |
||||
GOCMD=GO111MODULE=on go
|
||||
|
||||
linters-install: |
||||
@golangci-lint --version >/dev/null 2>&1 || { \
|
||||
echo "installing linting tools..."; \
|
||||
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.41.1; \
|
||||
}
|
||||
|
||||
lint: linters-install |
||||
golangci-lint run
|
||||
|
||||
test: |
||||
$(GOCMD) test -cover -race ./...
|
||||
|
||||
bench: |
||||
$(GOCMD) test -bench=. -benchmem ./...
|
||||
|
||||
.PHONY: test lint linters-install |
@ -1,43 +1,348 @@ |
||||
Package go-validate-yourself |
||||
================ |
||||
[![Build Status](https://travis-ci.org/bluesuncorp/go-validate-yourself.svg?branch=v4)](https://travis-ci.org/bluesuncorp/go-validate-yourself) |
||||
[![GoDoc](https://godoc.org/gopkg.in/bluesuncorp/go-validate-yourself.v4?status.svg)](https://godoc.org/gopkg.in/bluesuncorp/go-validate-yourself.v4) |
||||
Package validator |
||||
================= |
||||
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v10/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) |
||||
![Project status](https://img.shields.io/badge/version-10.12.0-green.svg) |
||||
[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) |
||||
[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) |
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) |
||||
[![GoDoc](https://godoc.org/github.com/go-playground/validator?status.svg)](https://pkg.go.dev/github.com/go-playground/validator/v10) |
||||
![License](https://img.shields.io/dub/l/vibe-d.svg) |
||||
|
||||
Package validator implements value validations for structs and individual fields based on tags. |
||||
|
||||
It has the following **unique** features: |
||||
|
||||
- Cross Field and Cross Struct validations by using validation tags or custom validators. |
||||
- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated. |
||||
- Ability to dive into both map keys and values for validation |
||||
- Handles type interface by determining it's underlying type prior to validation. |
||||
- Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29) |
||||
- Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs |
||||
- Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError |
||||
- Customizable i18n aware error messages. |
||||
- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding) |
||||
|
||||
Installation |
||||
============ |
||||
------------ |
||||
|
||||
Use go get. |
||||
|
||||
go get github.com/go-playground/validator/v10 |
||||
|
||||
Then import the validator package into your own code. |
||||
|
||||
import "github.com/go-playground/validator/v10" |
||||
|
||||
Error Return Value |
||||
------- |
||||
|
||||
Validation functions return type error |
||||
|
||||
They return type error to avoid the issue discussed in the following, where err is always != nil: |
||||
|
||||
* http://stackoverflow.com/a/29138676/3158232 |
||||
* https://github.com/go-playground/validator/issues/134 |
||||
|
||||
Validator returns only InvalidValidationError for bad validation input, nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so: |
||||
|
||||
Just use go get. |
||||
```go |
||||
err := validate.Struct(mystruct) |
||||
validationErrors := err.(validator.ValidationErrors) |
||||
``` |
||||
|
||||
go get gopkg.in/bluesuncorp/go-validate-yourself.v4 |
||||
Usage and documentation |
||||
------ |
||||
|
||||
or to update |
||||
Please see https://pkg.go.dev/github.com/go-playground/validator/v10 for detailed usage docs. |
||||
|
||||
go get -u gopkg.in/bluesuncorp/go-validate-yourself.v4 |
||||
##### Examples: |
||||
|
||||
And then just import the package into your own code. |
||||
- [Simple](https://github.com/go-playground/validator/blob/master/_examples/simple/main.go) |
||||
- [Custom Field Types](https://github.com/go-playground/validator/blob/master/_examples/custom/main.go) |
||||
- [Struct Level](https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go) |
||||
- [Translations & Custom Errors](https://github.com/go-playground/validator/blob/master/_examples/translations/main.go) |
||||
- [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding) |
||||
- [wash - an example application putting it all together](https://github.com/bluesuncorp/wash) |
||||
|
||||
import "gopkg.in/bluesuncorp/go-validate-yourself.v4" |
||||
Baked-in Validations |
||||
------ |
||||
|
||||
Usage |
||||
===== |
||||
### Fields: |
||||
|
||||
Please see http://godoc.org/gopkg.in/bluesuncorp/go-validate-yourself.v4 for detailed usage docs. |
||||
| Tag | Description | |
||||
| - | - | |
||||
| eqcsfield | Field Equals Another Field (relative)| |
||||
| eqfield | Field Equals Another Field | |
||||
| fieldcontains | Check the indicated characters are present in the Field | |
||||
| fieldexcludes | Check the indicated characters are not present in the field | |
||||
| gtcsfield | Field Greater Than Another Relative Field | |
||||
| gtecsfield | Field Greater Than or Equal To Another Relative Field | |
||||
| gtefield | Field Greater Than or Equal To Another Field | |
||||
| gtfield | Field Greater Than Another Field | |
||||
| ltcsfield | Less Than Another Relative Field | |
||||
| ltecsfield | Less Than or Equal To Another Relative Field | |
||||
| ltefield | Less Than or Equal To Another Field | |
||||
| ltfield | Less Than Another Field | |
||||
| necsfield | Field Does Not Equal Another Field (relative) | |
||||
| nefield | Field Does Not Equal Another Field | |
||||
|
||||
Contributing |
||||
============ |
||||
### Network: |
||||
|
||||
There will be a development branch for each version of this package i.e. v1-development, please |
||||
make your pull requests against those branches. |
||||
| Tag | Description | |
||||
| - | - | |
||||
| cidr | Classless Inter-Domain Routing CIDR | |
||||
| cidrv4 | Classless Inter-Domain Routing CIDRv4 | |
||||
| cidrv6 | Classless Inter-Domain Routing CIDRv6 | |
||||
| datauri | Data URL | |
||||
| fqdn | Full Qualified Domain Name (FQDN) | |
||||
| hostname | Hostname RFC 952 | |
||||
| hostname_port | HostPort | |
||||
| hostname_rfc1123 | Hostname RFC 1123 | |
||||
| ip | Internet Protocol Address IP | |
||||
| ip4_addr | Internet Protocol Address IPv4 | |
||||
| ip6_addr | Internet Protocol Address IPv6 | |
||||
| ip_addr | Internet Protocol Address IP | |
||||
| ipv4 | Internet Protocol Address IPv4 | |
||||
| ipv6 | Internet Protocol Address IPv6 | |
||||
| mac | Media Access Control Address MAC | |
||||
| tcp4_addr | Transmission Control Protocol Address TCPv4 | |
||||
| tcp6_addr | Transmission Control Protocol Address TCPv6 | |
||||
| tcp_addr | Transmission Control Protocol Address TCP | |
||||
| udp4_addr | User Datagram Protocol Address UDPv4 | |
||||
| udp6_addr | User Datagram Protocol Address UDPv6 | |
||||
| udp_addr | User Datagram Protocol Address UDP | |
||||
| unix_addr | Unix domain socket end point Address | |
||||
| uri | URI String | |
||||
| url | URL String | |
||||
| http_url | HTTP URL String | |
||||
| url_encoded | URL Encoded | |
||||
| urn_rfc2141 | Urn RFC 2141 String | |
||||
|
||||
If changes are breaking please create an issue, for discussion and create a pull request against |
||||
the highest development branch for example this package has a v1 and v1-development branch |
||||
however, there will also be a v2-development brach even though v2 doesn't exist yet. |
||||
### Strings: |
||||
|
||||
I strongly encourage everyone whom creates a custom validation function to contribute them and |
||||
help make this package even better. |
||||
| Tag | Description | |
||||
| - | - | |
||||
| alpha | Alpha Only | |
||||
| alphanum | Alphanumeric | |
||||
| alphanumunicode | Alphanumeric Unicode | |
||||
| alphaunicode | Alpha Unicode | |
||||
| ascii | ASCII | |
||||
| boolean | Boolean | |
||||
| contains | Contains | |
||||
| containsany | Contains Any | |
||||
| containsrune | Contains Rune | |
||||
| endsnotwith | Ends Not With | |
||||
| endswith | Ends With | |
||||
| excludes | Excludes | |
||||
| excludesall | Excludes All | |
||||
| excludesrune | Excludes Rune | |
||||
| lowercase | Lowercase | |
||||
| multibyte | Multi-Byte Characters | |
||||
| number | Number | |
||||
| numeric | Numeric | |
||||
| printascii | Printable ASCII | |
||||
| startsnotwith | Starts Not With | |
||||
| startswith | Starts With | |
||||
| uppercase | Uppercase | |
||||
|
||||
### Format: |
||||
| Tag | Description | |
||||
| - | - | |
||||
| base64 | Base64 String | |
||||
| base64url | Base64URL String | |
||||
| base64rawurl | Base64RawURL String | |
||||
| bic | Business Identifier Code (ISO 9362) | |
||||
| bcp47_language_tag | Language tag (BCP 47) | |
||||
| btc_addr | Bitcoin Address | |
||||
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | |
||||
| credit_card | Credit Card Number | |
||||
| mongodb | MongoDB ObjectID | |
||||
| cron | Cron | |
||||
| datetime | Datetime | |
||||
| e164 | e164 formatted phone number | |
||||
| email | E-mail String |
||||
| eth_addr | Ethereum Address | |
||||
| hexadecimal | Hexadecimal String | |
||||
| hexcolor | Hexcolor String | |
||||
| hsl | HSL String | |
||||
| hsla | HSLA String | |
||||
| html | HTML Tags | |
||||
| html_encoded | HTML Encoded | |
||||
| isbn | International Standard Book Number | |
||||
| isbn10 | International Standard Book Number 10 | |
||||
| isbn13 | International Standard Book Number 13 | |
||||
| iso3166_1_alpha2 | Two-letter country code (ISO 3166-1 alpha-2) | |
||||
| iso3166_1_alpha3 | Three-letter country code (ISO 3166-1 alpha-3) | |
||||
| iso3166_1_alpha_numeric | Numeric country code (ISO 3166-1 numeric) | |
||||
| iso3166_2 | Country subdivision code (ISO 3166-2) | |
||||
| iso4217 | Currency code (ISO 4217) | |
||||
| json | JSON | |
||||
| jwt | JSON Web Token (JWT) | |
||||
| latitude | Latitude | |
||||
| longitude | Longitude | |
||||
| luhn_checksum | Luhn Algorithm Checksum (for strings and (u)int) | |
||||
| postcode_iso3166_alpha2 | Postcode | |
||||
| postcode_iso3166_alpha2_field | Postcode | |
||||
| rgb | RGB String | |
||||
| rgba | RGBA String | |
||||
| ssn | Social Security Number SSN | |
||||
| timezone | Timezone | |
||||
| uuid | Universally Unique Identifier UUID | |
||||
| uuid3 | Universally Unique Identifier UUID v3 | |
||||
| uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 | |
||||
| uuid4 | Universally Unique Identifier UUID v4 | |
||||
| uuid4_rfc4122 | Universally Unique Identifier UUID v4 RFC4122 | |
||||
| uuid5 | Universally Unique Identifier UUID v5 | |
||||
| uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 | |
||||
| uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 | |
||||
| md4 | MD4 hash | |
||||
| md5 | MD5 hash | |
||||
| sha256 | SHA256 hash | |
||||
| sha384 | SHA384 hash | |
||||
| sha512 | SHA512 hash | |
||||
| ripemd128 | RIPEMD-128 hash | |
||||
| ripemd128 | RIPEMD-160 hash | |
||||
| tiger128 | TIGER128 hash | |
||||
| tiger160 | TIGER160 hash | |
||||
| tiger192 | TIGER192 hash | |
||||
| semver | Semantic Versioning 2.0.0 | |
||||
| ulid | Universally Unique Lexicographically Sortable Identifier ULID | |
||||
| cve | Common Vulnerabilities and Exposures Identifier (CVE id) | |
||||
|
||||
### Comparisons: |
||||
| Tag | Description | |
||||
| - | - | |
||||
| eq | Equals | |
||||
| eq_ignore_case | Equals ignoring case | |
||||
| gt | Greater than| |
||||
| gte | Greater than or equal | |
||||
| lt | Less Than | |
||||
| lte | Less Than or Equal | |
||||
| ne | Not Equal | |
||||
| ne_ignore_case | Not Equal ignoring case | |
||||
|
||||
### Other: |
||||
| Tag | Description | |
||||
| - | - | |
||||
| dir | Existing Directory | |
||||
| dirpath | Directory Path | |
||||
| file | Existing File | |
||||
| filepath | File Path | |
||||
| isdefault | Is Default | |
||||
| len | Length | |
||||
| max | Maximum | |
||||
| min | Minimum | |
||||
| oneof | One Of | |
||||
| required | Required | |
||||
| required_if | Required If | |
||||
| required_unless | Required Unless | |
||||
| required_with | Required With | |
||||
| required_with_all | Required With All | |
||||
| required_without | Required Without | |
||||
| required_without_all | Required Without All | |
||||
| excluded_if | Excluded If | |
||||
| excluded_unless | Excluded Unless | |
||||
| excluded_with | Excluded With | |
||||
| excluded_with_all | Excluded With All | |
||||
| excluded_without | Excluded Without | |
||||
| excluded_without_all | Excluded Without All | |
||||
| unique | Unique | |
||||
|
||||
#### Aliases: |
||||
| Tag | Description | |
||||
| - | - | |
||||
| iscolor | hexcolor\|rgb\|rgba\|hsl\|hsla | |
||||
| country_code | iso3166_1_alpha2\|iso3166_1_alpha3\|iso3166_1_alpha_numeric | |
||||
|
||||
Benchmarks |
||||
------ |
||||
###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64 |
||||
```go |
||||
goos: darwin |
||||
goarch: amd64 |
||||
pkg: github.com/go-playground/validator |
||||
BenchmarkFieldSuccess-8 20000000 83.6 ns/op 0 B/op 0 allocs/op |
||||
BenchmarkFieldSuccessParallel-8 50000000 26.8 ns/op 0 B/op 0 allocs/op |
||||
BenchmarkFieldFailure-8 5000000 291 ns/op 208 B/op 4 allocs/op |
||||
BenchmarkFieldFailureParallel-8 20000000 107 ns/op 208 B/op 4 allocs/op |
||||
BenchmarkFieldArrayDiveSuccess-8 2000000 623 ns/op 201 B/op 11 allocs/op |
||||
BenchmarkFieldArrayDiveSuccessParallel-8 10000000 237 ns/op 201 B/op 11 allocs/op |
||||
BenchmarkFieldArrayDiveFailure-8 2000000 859 ns/op 412 B/op 16 allocs/op |
||||
BenchmarkFieldArrayDiveFailureParallel-8 5000000 335 ns/op 413 B/op 16 allocs/op |
||||
BenchmarkFieldMapDiveSuccess-8 1000000 1292 ns/op 432 B/op 18 allocs/op |
||||
BenchmarkFieldMapDiveSuccessParallel-8 3000000 467 ns/op 432 B/op 18 allocs/op |
||||
BenchmarkFieldMapDiveFailure-8 1000000 1082 ns/op 512 B/op 16 allocs/op |
||||
BenchmarkFieldMapDiveFailureParallel-8 5000000 425 ns/op 512 B/op 16 allocs/op |
||||
BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1539 ns/op 480 B/op 21 allocs/op |
||||
BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 613 ns/op 480 B/op 21 allocs/op |
||||
BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1413 ns/op 721 B/op 21 allocs/op |
||||
BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 575 ns/op 721 B/op 21 allocs/op |
||||
BenchmarkFieldCustomTypeSuccess-8 10000000 216 ns/op 32 B/op 2 allocs/op |
||||
BenchmarkFieldCustomTypeSuccessParallel-8 20000000 82.2 ns/op 32 B/op 2 allocs/op |
||||
BenchmarkFieldCustomTypeFailure-8 5000000 274 ns/op 208 B/op 4 allocs/op |
||||
BenchmarkFieldCustomTypeFailureParallel-8 20000000 116 ns/op 208 B/op 4 allocs/op |
||||
BenchmarkFieldOrTagSuccess-8 2000000 740 ns/op 16 B/op 1 allocs/op |
||||
BenchmarkFieldOrTagSuccessParallel-8 3000000 474 ns/op 16 B/op 1 allocs/op |
||||
BenchmarkFieldOrTagFailure-8 3000000 471 ns/op 224 B/op 5 allocs/op |
||||
BenchmarkFieldOrTagFailureParallel-8 3000000 414 ns/op 224 B/op 5 allocs/op |
||||
BenchmarkStructLevelValidationSuccess-8 10000000 213 ns/op 32 B/op 2 allocs/op |
||||
BenchmarkStructLevelValidationSuccessParallel-8 20000000 91.8 ns/op 32 B/op 2 allocs/op |
||||
BenchmarkStructLevelValidationFailure-8 3000000 473 ns/op 304 B/op 8 allocs/op |
||||
BenchmarkStructLevelValidationFailureParallel-8 10000000 234 ns/op 304 B/op 8 allocs/op |
||||
BenchmarkStructSimpleCustomTypeSuccess-8 5000000 385 ns/op 32 B/op 2 allocs/op |
||||
BenchmarkStructSimpleCustomTypeSuccessParallel-8 10000000 161 ns/op 32 B/op 2 allocs/op |
||||
BenchmarkStructSimpleCustomTypeFailure-8 2000000 640 ns/op 424 B/op 9 allocs/op |
||||
BenchmarkStructSimpleCustomTypeFailureParallel-8 5000000 318 ns/op 440 B/op 10 allocs/op |
||||
BenchmarkStructFilteredSuccess-8 2000000 597 ns/op 288 B/op 9 allocs/op |
||||
BenchmarkStructFilteredSuccessParallel-8 10000000 266 ns/op 288 B/op 9 allocs/op |
||||
BenchmarkStructFilteredFailure-8 3000000 454 ns/op 256 B/op 7 allocs/op |
||||
BenchmarkStructFilteredFailureParallel-8 10000000 214 ns/op 256 B/op 7 allocs/op |
||||
BenchmarkStructPartialSuccess-8 3000000 502 ns/op 256 B/op 6 allocs/op |
||||
BenchmarkStructPartialSuccessParallel-8 10000000 225 ns/op 256 B/op 6 allocs/op |
||||
BenchmarkStructPartialFailure-8 2000000 702 ns/op 480 B/op 11 allocs/op |
||||
BenchmarkStructPartialFailureParallel-8 5000000 329 ns/op 480 B/op 11 allocs/op |
||||
BenchmarkStructExceptSuccess-8 2000000 793 ns/op 496 B/op 12 allocs/op |
||||
BenchmarkStructExceptSuccessParallel-8 10000000 193 ns/op 240 B/op 5 allocs/op |
||||
BenchmarkStructExceptFailure-8 2000000 639 ns/op 464 B/op 10 allocs/op |
||||
BenchmarkStructExceptFailureParallel-8 5000000 300 ns/op 464 B/op 10 allocs/op |
||||
BenchmarkStructSimpleCrossFieldSuccess-8 3000000 417 ns/op 72 B/op 3 allocs/op |
||||
BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 163 ns/op 72 B/op 3 allocs/op |
||||
BenchmarkStructSimpleCrossFieldFailure-8 2000000 645 ns/op 304 B/op 8 allocs/op |
||||
BenchmarkStructSimpleCrossFieldFailureParallel-8 5000000 285 ns/op 304 B/op 8 allocs/op |
||||
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3000000 588 ns/op 80 B/op 4 allocs/op |
||||
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 221 ns/op 80 B/op 4 allocs/op |
||||
BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 868 ns/op 320 B/op 9 allocs/op |
||||
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 337 ns/op 320 B/op 9 allocs/op |
||||
BenchmarkStructSimpleSuccess-8 5000000 260 ns/op 0 B/op 0 allocs/op |
||||
BenchmarkStructSimpleSuccessParallel-8 20000000 90.6 ns/op 0 B/op 0 allocs/op |
||||
BenchmarkStructSimpleFailure-8 2000000 619 ns/op 424 B/op 9 allocs/op |
||||
BenchmarkStructSimpleFailureParallel-8 5000000 296 ns/op 424 B/op 9 allocs/op |
||||
BenchmarkStructComplexSuccess-8 1000000 1454 ns/op 128 B/op 8 allocs/op |
||||
BenchmarkStructComplexSuccessParallel-8 3000000 579 ns/op 128 B/op 8 allocs/op |
||||
BenchmarkStructComplexFailure-8 300000 4140 ns/op 3041 B/op 53 allocs/op |
||||
BenchmarkStructComplexFailureParallel-8 1000000 2127 ns/op 3041 B/op 53 allocs/op |
||||
BenchmarkOneof-8 10000000 140 ns/op 0 B/op 0 allocs/op |
||||
BenchmarkOneofParallel-8 20000000 70.1 ns/op 0 B/op 0 allocs/op |
||||
``` |
||||
|
||||
Complementary Software |
||||
---------------------- |
||||
|
||||
Here is a list of software that complements using this library either pre or post validation. |
||||
|
||||
* [form](https://github.com/go-playground/form) - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support. |
||||
* [mold](https://github.com/go-playground/mold) - A general library to help modify or set data within data structures and other objects |
||||
|
||||
How to Contribute |
||||
------ |
||||
|
||||
Make a pull request... |
||||
|
||||
License |
||||
======= |
||||
Distributed under MIT License, please see license file in code for more details. |
||||
------- |
||||
Distributed under MIT License, please see license file within the code for more details. |
||||
|
||||
Maintainers |
||||
----------- |
||||
This project has grown large enough that more than one person is required to properly support the community. |
||||
If you are interested in becoming a maintainer please reach out to me https://github.com/deankarn |
||||
|
@ -0,0 +1,39 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
// MyStruct ..
|
||||
type MyStruct struct { |
||||
String string `validate:"is-awesome"` |
||||
} |
||||
|
||||
// use a single instance of Validate, it caches struct info
|
||||
var validate *validator.Validate |
||||
|
||||
func main() { |
||||
|
||||
validate = validator.New() |
||||
validate.RegisterValidation("is-awesome", ValidateMyVal) |
||||
|
||||
s := MyStruct{String: "awesome"} |
||||
|
||||
err := validate.Struct(s) |
||||
if err != nil { |
||||
fmt.Printf("Err(s):\n%+v\n", err) |
||||
} |
||||
|
||||
s.String = "not awesome" |
||||
err = validate.Struct(s) |
||||
if err != nil { |
||||
fmt.Printf("Err(s):\n%+v\n", err) |
||||
} |
||||
} |
||||
|
||||
// ValidateMyVal implements validator.Func
|
||||
func ValidateMyVal(fl validator.FieldLevel) bool { |
||||
return fl.Field().String() == "awesome" |
||||
} |
@ -0,0 +1,51 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"database/sql" |
||||
"database/sql/driver" |
||||
"fmt" |
||||
"reflect" |
||||
|
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
// DbBackedUser User struct
|
||||
type DbBackedUser struct { |
||||
Name sql.NullString `validate:"required"` |
||||
Age sql.NullInt64 `validate:"required"` |
||||
} |
||||
|
||||
// use a single instance of Validate, it caches struct info
|
||||
var validate *validator.Validate |
||||
|
||||
func main() { |
||||
|
||||
validate = validator.New() |
||||
|
||||
// register all sql.Null* types to use the ValidateValuer CustomTypeFunc
|
||||
validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) |
||||
|
||||
// build object for validation
|
||||
x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}} |
||||
|
||||
err := validate.Struct(x) |
||||
|
||||
if err != nil { |
||||
fmt.Printf("Err(s):\n%+v\n", err) |
||||
} |
||||
} |
||||
|
||||
// ValidateValuer implements validator.CustomTypeFunc
|
||||
func ValidateValuer(field reflect.Value) interface{} { |
||||
|
||||
if valuer, ok := field.Interface().(driver.Valuer); ok { |
||||
|
||||
val, err := valuer.Value() |
||||
if err == nil { |
||||
return val |
||||
} |
||||
// handle the error how you want
|
||||
} |
||||
|
||||
return nil |
||||
} |
@ -0,0 +1,39 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
// Test ...
|
||||
type Test struct { |
||||
Array []string `validate:"required,gt=0,dive,required"` |
||||
Map map[string]string `validate:"required,gt=0,dive,keys,keymax,endkeys,required,max=1000"` |
||||
} |
||||
|
||||
// use a single instance of Validate, it caches struct info
|
||||
var validate *validator.Validate |
||||
|
||||
func main() { |
||||
|
||||
validate = validator.New() |
||||
|
||||
// registering alias so we can see the differences between
|
||||
// map key, value validation errors
|
||||
validate.RegisterAlias("keymax", "max=10") |
||||
|
||||
var test Test |
||||
|
||||
val(test) |
||||
|
||||
test.Array = []string{""} |
||||
test.Map = map[string]string{"test > than 10": ""} |
||||
val(test) |
||||
} |
||||
|
||||
func val(test Test) { |
||||
fmt.Println("testing") |
||||
err := validate.Struct(test) |
||||
fmt.Println(err) |
||||
} |
@ -0,0 +1,10 @@ |
||||
package main |
||||
|
||||
import "github.com/gin-gonic/gin/binding" |
||||
|
||||
func main() { |
||||
|
||||
binding.Validator = new(defaultValidator) |
||||
|
||||
// regular gin logic
|
||||
} |
@ -0,0 +1,55 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"reflect" |
||||
"sync" |
||||
|
||||
"github.com/gin-gonic/gin/binding" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
type defaultValidator struct { |
||||
once sync.Once |
||||
validate *validator.Validate |
||||
} |
||||
|
||||
var _ binding.StructValidator = &defaultValidator{} |
||||
|
||||
func (v *defaultValidator) ValidateStruct(obj interface{}) error { |
||||
|
||||
if kindOfData(obj) == reflect.Struct { |
||||
|
||||
v.lazyinit() |
||||
|
||||
if err := v.validate.Struct(obj); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (v *defaultValidator) Engine() interface{} { |
||||
v.lazyinit() |
||||
return v.validate |
||||
} |
||||
|
||||
func (v *defaultValidator) lazyinit() { |
||||
v.once.Do(func() { |
||||
v.validate = validator.New() |
||||
v.validate.SetTagName("binding") |
||||
|
||||
// add any custom validations etc. here
|
||||
}) |
||||
} |
||||
|
||||
func kindOfData(data interface{}) reflect.Kind { |
||||
|
||||
value := reflect.ValueOf(data) |
||||
valueType := value.Kind() |
||||
|
||||
if valueType == reflect.Ptr { |
||||
valueType = value.Elem().Kind() |
||||
} |
||||
return valueType |
||||
} |
@ -0,0 +1,87 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
var validate *validator.Validate |
||||
|
||||
func main() { |
||||
validate = validator.New() |
||||
|
||||
validateMap() |
||||
validateNestedMap() |
||||
} |
||||
|
||||
func validateMap() { |
||||
user := map[string]interface{}{"name": "Arshiya Kiani", "email": "zytel3301@gmail.com"} |
||||
|
||||
// Every rule will be applied to the item of the data that the offset of rule is pointing to.
|
||||
// So if you have a field "email": "omitempty,required,email", the validator will apply these
|
||||
// rules to offset of email in user data
|
||||
rules := map[string]interface{}{"name": "required,min=8,max=32", "email": "omitempty,required,email"} |
||||
|
||||
// ValidateMap will return map[string]error.
|
||||
// The offset of every item in errs is the name of invalid field and the value
|
||||
// is the message of error. If there was no error, ValidateMap method will
|
||||
// return an EMPTY map of errors, not nil. If you want to check that
|
||||
// if there was an error or not, you must check the length of the return value
|
||||
errs := validate.ValidateMap(user, rules) |
||||
|
||||
if len(errs) > 0 { |
||||
fmt.Println(errs) |
||||
// The user is invalid
|
||||
} |
||||
|
||||
// The user is valid
|
||||
} |
||||
|
||||
func validateNestedMap() { |
||||
|
||||
data := map[string]interface{}{ |
||||
"name": "Arshiya Kiani", |
||||
"email": "zytel3301@gmail.com", |
||||
"details": map[string]interface{}{ |
||||
"family_members": map[string]interface{}{ |
||||
"father_name": "Micheal", |
||||
"mother_name": "Hannah", |
||||
}, |
||||
"salary": "1000", |
||||
"phones": []map[string]interface{}{ |
||||
{ |
||||
"number": "11-111-1111", |
||||
"remark": "home", |
||||
}, |
||||
{ |
||||
"number": "22-222-2222", |
||||
"remark": "work", |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
// Rules must be set as the structure as the data itself. If you want to dive into the
|
||||
// map, just declare its rules as a map
|
||||
rules := map[string]interface{}{ |
||||
"name": "min=4,max=32", |
||||
"email": "required,email", |
||||
"details": map[string]interface{}{ |
||||
"family_members": map[string]interface{}{ |
||||
"father_name": "required,min=4,max=32", |
||||
"mother_name": "required,min=4,max=32", |
||||
}, |
||||
"salary": "number", |
||||
"phones": map[string]interface{}{ |
||||
"number": "required,min=4,max=32", |
||||
"remark": "required,min=1,max=32", |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
if len(validate.ValidateMap(data, rules)) == 0 { |
||||
// Data is valid
|
||||
} |
||||
|
||||
// Data is invalid
|
||||
} |
@ -0,0 +1,101 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
// User contains user information
|
||||
type User struct { |
||||
FirstName string `validate:"required"` |
||||
LastName string `validate:"required"` |
||||
Age uint8 `validate:"gte=0,lte=130"` |
||||
Email string `validate:"required,email"` |
||||
FavouriteColor string `validate:"iscolor"` // alias for 'hexcolor|rgb|rgba|hsl|hsla'
|
||||
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
|
||||
} |
||||
|
||||
// Address houses a users address information
|
||||
type Address struct { |
||||
Street string `validate:"required"` |
||||
City string `validate:"required"` |
||||
Planet string `validate:"required"` |
||||
Phone string `validate:"required"` |
||||
} |
||||
|
||||
// use a single instance of Validate, it caches struct info
|
||||
var validate *validator.Validate |
||||
|
||||
func main() { |
||||
|
||||
validate = validator.New() |
||||
|
||||
validateStruct() |
||||
validateVariable() |
||||
} |
||||
|
||||
func validateStruct() { |
||||
|
||||
address := &Address{ |
||||
Street: "Eavesdown Docks", |
||||
Planet: "Persphone", |
||||
Phone: "none", |
||||
} |
||||
|
||||
user := &User{ |
||||
FirstName: "Badger", |
||||
LastName: "Smith", |
||||
Age: 135, |
||||
Email: "Badger.Smith@gmail.com", |
||||
FavouriteColor: "#000-", |
||||
Addresses: []*Address{address}, |
||||
} |
||||
|
||||
// returns nil or ValidationErrors ( []FieldError )
|
||||
err := validate.Struct(user) |
||||
if err != nil { |
||||
|
||||
// this check is only needed when your code could produce
|
||||
// an invalid value for validation such as interface with nil
|
||||
// value most including myself do not usually have code like this.
|
||||
if _, ok := err.(*validator.InvalidValidationError); ok { |
||||
fmt.Println(err) |
||||
return |
||||
} |
||||
|
||||
for _, err := range err.(validator.ValidationErrors) { |
||||
|
||||
fmt.Println(err.Namespace()) |
||||
fmt.Println(err.Field()) |
||||
fmt.Println(err.StructNamespace()) |
||||
fmt.Println(err.StructField()) |
||||
fmt.Println(err.Tag()) |
||||
fmt.Println(err.ActualTag()) |
||||
fmt.Println(err.Kind()) |
||||
fmt.Println(err.Type()) |
||||
fmt.Println(err.Value()) |
||||
fmt.Println(err.Param()) |
||||
fmt.Println() |
||||
} |
||||
|
||||
// from here you can create your own error messages in whatever language you wish
|
||||
return |
||||
} |
||||
|
||||
// save user to database
|
||||
} |
||||
|
||||
func validateVariable() { |
||||
|
||||
myEmail := "joeybloggs.gmail.com" |
||||
|
||||
errs := validate.Var(myEmail, "required,email") |
||||
|
||||
if errs != nil { |
||||
fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "email" tag
|
||||
return |
||||
} |
||||
|
||||
// email ok, move on
|
||||
} |
@ -0,0 +1,172 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
"reflect" |
||||
"strings" |
||||
|
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
type validationError struct { |
||||
Namespace string `json:"namespace"` // can differ when a custom TagNameFunc is registered or
|
||||
Field string `json:"field"` // by passing alt name to ReportError like below
|
||||
StructNamespace string `json:"structNamespace"` |
||||
StructField string `json:"structField"` |
||||
Tag string `json:"tag"` |
||||
ActualTag string `json:"actualTag"` |
||||
Kind string `json:"kind"` |
||||
Type string `json:"type"` |
||||
Value string `json:"value"` |
||||
Param string `json:"param"` |
||||
Message string `json:"message"` |
||||
} |
||||
|
||||
type Gender uint |
||||
|
||||
const ( |
||||
Male Gender = iota + 1 |
||||
Female |
||||
Intersex |
||||
) |
||||
|
||||
func (gender Gender) String() string { |
||||
terms := []string{"Male", "Female", "Intersex"} |
||||
if gender < Male || gender > Intersex { |
||||
return "unknown" |
||||
} |
||||
return terms[gender] |
||||
} |
||||
|
||||
// User contains user information
|
||||
type User struct { |
||||
FirstName string `json:"fname"` |
||||
LastName string `json:"lname"` |
||||
Age uint8 `validate:"gte=0,lte=130"` |
||||
Email string `json:"e-mail" validate:"required,email"` |
||||
FavouriteColor string `validate:"hexcolor|rgb|rgba"` |
||||
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
|
||||
Gender Gender `json:"gender" validate:"required,gender_custom_validation"` |
||||
} |
||||
|
||||
// Address houses a users address information
|
||||
type Address struct { |
||||
Street string `validate:"required"` |
||||
City string `validate:"required"` |
||||
Planet string `validate:"required"` |
||||
Phone string `validate:"required"` |
||||
} |
||||
|
||||
// use a single instance of Validate, it caches struct info
|
||||
var validate *validator.Validate |
||||
|
||||
func main() { |
||||
|
||||
validate = validator.New() |
||||
|
||||
// register function to get tag name from json tags.
|
||||
validate.RegisterTagNameFunc(func(fld reflect.StructField) string { |
||||
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] |
||||
if name == "-" { |
||||
return "" |
||||
} |
||||
return name |
||||
}) |
||||
|
||||
// register validation for 'User'
|
||||
// NOTE: only have to register a non-pointer type for 'User', validator
|
||||
// internally dereferences during it's type checks.
|
||||
validate.RegisterStructValidation(UserStructLevelValidation, User{}) |
||||
|
||||
// register a custom validation for user genre on a line
|
||||
// validates that an enum is within the interval
|
||||
err := validate.RegisterValidation("gender_custom_validation", func(fl validator.FieldLevel) bool { |
||||
value := fl.Field().Interface().(Gender) |
||||
return value.String() != "unknown" |
||||
}) |
||||
if err != nil { |
||||
fmt.Println(err) |
||||
return |
||||
} |
||||
|
||||
// build 'User' info, normally posted data etc...
|
||||
address := &Address{ |
||||
Street: "Eavesdown Docks", |
||||
Planet: "Persphone", |
||||
Phone: "none", |
||||
City: "Unknown", |
||||
} |
||||
|
||||
user := &User{ |
||||
FirstName: "", |
||||
LastName: "", |
||||
Age: 45, |
||||
Email: "Badger.Smith@gmail", |
||||
FavouriteColor: "#000", |
||||
Addresses: []*Address{address}, |
||||
} |
||||
|
||||
// returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError )
|
||||
err = validate.Struct(user) |
||||
if err != nil { |
||||
|
||||
// this check is only needed when your code could produce
|
||||
// an invalid value for validation such as interface with nil
|
||||
// value most including myself do not usually have code like this.
|
||||
if _, ok := err.(*validator.InvalidValidationError); ok { |
||||
fmt.Println(err) |
||||
return |
||||
} |
||||
|
||||
for _, err := range err.(validator.ValidationErrors) { |
||||
e := validationError{ |
||||
Namespace: err.Namespace(), |
||||
Field: err.Field(), |
||||
StructNamespace: err.StructNamespace(), |
||||
StructField: err.StructField(), |
||||
Tag: err.Tag(), |
||||
ActualTag: err.ActualTag(), |
||||
Kind: fmt.Sprintf("%v", err.Kind()), |
||||
Type: fmt.Sprintf("%v", err.Type()), |
||||
Value: fmt.Sprintf("%v", err.Value()), |
||||
Param: err.Param(), |
||||
Message: err.Error(), |
||||
} |
||||
|
||||
indent, err := json.MarshalIndent(e, "", " ") |
||||
if err != nil { |
||||
fmt.Println(err) |
||||
panic(err) |
||||
} |
||||
|
||||
fmt.Println(string(indent)) |
||||
} |
||||
|
||||
// from here you can create your own error messages in whatever language you wish
|
||||
return |
||||
} |
||||
|
||||
// save user to database
|
||||
} |
||||
|
||||
// UserStructLevelValidation contains custom struct level validations that don't always
|
||||
// make sense at the field validation level. For Example this function validates that either
|
||||
// FirstName or LastName exist; could have done that with a custom field validation but then
|
||||
// would have had to add it to both fields duplicating the logic + overhead, this way it's
|
||||
// only validated once.
|
||||
//
|
||||
// NOTE: you may ask why wouldn't I just do this outside of validator, because doing this way
|
||||
// hooks right into validator and you can combine with validation tags and still have a
|
||||
// common error output format.
|
||||
func UserStructLevelValidation(sl validator.StructLevel) { |
||||
|
||||
user := sl.Current().Interface().(User) |
||||
|
||||
if len(user.FirstName) == 0 && len(user.LastName) == 0 { |
||||
sl.ReportError(user.FirstName, "fname", "FirstName", "fnameorlname", "") |
||||
sl.ReportError(user.LastName, "lname", "LastName", "fnameorlname", "") |
||||
} |
||||
|
||||
// plus can do more, even with different tag than "fnameorlname"
|
||||
} |
@ -0,0 +1,92 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
type Data struct { |
||||
Name string |
||||
Email string |
||||
Details *Details |
||||
} |
||||
|
||||
type Details struct { |
||||
FamilyMembers *FamilyMembers |
||||
Salary string |
||||
} |
||||
|
||||
type FamilyMembers struct { |
||||
FatherName string |
||||
MotherName string |
||||
} |
||||
|
||||
type Data2 struct { |
||||
Name string |
||||
Age uint32 |
||||
} |
||||
|
||||
var validate = validator.New() |
||||
|
||||
func main() { |
||||
validateStruct() |
||||
// output
|
||||
// Key: 'Data2.Name' Error:Field validation for 'Name' failed on the 'min' tag
|
||||
// Key: 'Data2.Age' Error:Field validation for 'Age' failed on the 'max' tag
|
||||
|
||||
validateStructNested() |
||||
// output
|
||||
// Key: 'Data.Name' Error:Field validation for 'Name' failed on the 'max' tag
|
||||
// Key: 'Data.Details.FamilyMembers' Error:Field validation for 'FamilyMembers' failed on the 'required' tag
|
||||
} |
||||
|
||||
func validateStruct() { |
||||
data := Data2{ |
||||
Name: "leo", |
||||
Age: 1000, |
||||
} |
||||
|
||||
rules := map[string]string{ |
||||
"Name": "min=4,max=6", |
||||
"Age": "min=4,max=6", |
||||
} |
||||
|
||||
validate.RegisterStructValidationMapRules(rules, Data2{}) |
||||
|
||||
err := validate.Struct(data) |
||||
fmt.Println(err) |
||||
fmt.Println() |
||||
} |
||||
|
||||
func validateStructNested() { |
||||
data := Data{ |
||||
Name: "11sdfddd111", |
||||
Email: "zytel3301@mail.com", |
||||
Details: &Details{ |
||||
Salary: "1000", |
||||
}, |
||||
} |
||||
|
||||
rules1 := map[string]string{ |
||||
"Name": "min=4,max=6", |
||||
"Email": "required,email", |
||||
"Details": "required", |
||||
} |
||||
|
||||
rules2 := map[string]string{ |
||||
"Salary": "number", |
||||
"FamilyMembers": "required", |
||||
} |
||||
|
||||
rules3 := map[string]string{ |
||||
"FatherName": "required,min=4,max=32", |
||||
"MotherName": "required,min=4,max=32", |
||||
} |
||||
|
||||
validate.RegisterStructValidationMapRules(rules1, Data{}) |
||||
validate.RegisterStructValidationMapRules(rules2, Details{}) |
||||
validate.RegisterStructValidationMapRules(rules3, FamilyMembers{}) |
||||
err := validate.Struct(data) |
||||
|
||||
fmt.Println(err) |
||||
} |
@ -0,0 +1,129 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/go-playground/locales/en" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
en_translations "github.com/go-playground/validator/v10/translations/en" |
||||
) |
||||
|
||||
// User contains user information
|
||||
type User struct { |
||||
FirstName string `validate:"required"` |
||||
LastName string `validate:"required"` |
||||
Age uint8 `validate:"gte=0,lte=130"` |
||||
Email string `validate:"required,email"` |
||||
FavouriteColor string `validate:"iscolor"` // alias for 'hexcolor|rgb|rgba|hsl|hsla'
|
||||
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
|
||||
} |
||||
|
||||
// Address houses a users address information
|
||||
type Address struct { |
||||
Street string `validate:"required"` |
||||
City string `validate:"required"` |
||||
Planet string `validate:"required"` |
||||
Phone string `validate:"required"` |
||||
} |
||||
|
||||
// use a single instance , it caches struct info
|
||||
var ( |
||||
uni *ut.UniversalTranslator |
||||
validate *validator.Validate |
||||
) |
||||
|
||||
func main() { |
||||
|
||||
// NOTE: ommitting allot of error checking for brevity
|
||||
|
||||
en := en.New() |
||||
uni = ut.New(en, en) |
||||
|
||||
// this is usually know or extracted from http 'Accept-Language' header
|
||||
// also see uni.FindTranslator(...)
|
||||
trans, _ := uni.GetTranslator("en") |
||||
|
||||
validate = validator.New() |
||||
en_translations.RegisterDefaultTranslations(validate, trans) |
||||
|
||||
translateAll(trans) |
||||
translateIndividual(trans) |
||||
translateOverride(trans) // yep you can specify your own in whatever locale you want!
|
||||
} |
||||
|
||||
func translateAll(trans ut.Translator) { |
||||
|
||||
type User struct { |
||||
Username string `validate:"required"` |
||||
Tagline string `validate:"required,lt=10"` |
||||
Tagline2 string `validate:"required,gt=1"` |
||||
} |
||||
|
||||
user := User{ |
||||
Username: "Joeybloggs", |
||||
Tagline: "This tagline is way too long.", |
||||
Tagline2: "1", |
||||
} |
||||
|
||||
err := validate.Struct(user) |
||||
if err != nil { |
||||
|
||||
// translate all error at once
|
||||
errs := err.(validator.ValidationErrors) |
||||
|
||||
// returns a map with key = namespace & value = translated error
|
||||
// NOTICE: 2 errors are returned and you'll see something surprising
|
||||
// translations are i18n aware!!!!
|
||||
// eg. '10 characters' vs '1 character'
|
||||
fmt.Println(errs.Translate(trans)) |
||||
} |
||||
} |
||||
|
||||
func translateIndividual(trans ut.Translator) { |
||||
|
||||
type User struct { |
||||
Username string `validate:"required"` |
||||
} |
||||
|
||||
var user User |
||||
|
||||
err := validate.Struct(user) |
||||
if err != nil { |
||||
|
||||
errs := err.(validator.ValidationErrors) |
||||
|
||||
for _, e := range errs { |
||||
// can translate each error one at a time.
|
||||
fmt.Println(e.Translate(trans)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func translateOverride(trans ut.Translator) { |
||||
|
||||
validate.RegisterTranslation("required", trans, func(ut ut.Translator) error { |
||||
return ut.Add("required", "{0} must have a value!", true) // see universal-translator for details
|
||||
}, func(ut ut.Translator, fe validator.FieldError) string { |
||||
t, _ := ut.T("required", fe.Field()) |
||||
|
||||
return t |
||||
}) |
||||
|
||||
type User struct { |
||||
Username string `validate:"required"` |
||||
} |
||||
|
||||
var user User |
||||
|
||||
err := validate.Struct(user) |
||||
if err != nil { |
||||
|
||||
errs := err.(validator.ValidationErrors) |
||||
|
||||
for _, e := range errs { |
||||
// can translate each error one at a time.
|
||||
fmt.Println(e.Translate(trans)) |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,327 @@ |
||||
package validator |
||||
|
||||
import ( |
||||
"fmt" |
||||
"reflect" |
||||
"strings" |
||||
"sync" |
||||
"sync/atomic" |
||||
) |
||||
|
||||
type tagType uint8 |
||||
|
||||
const ( |
||||
typeDefault tagType = iota |
||||
typeOmitEmpty |
||||
typeIsDefault |
||||
typeNoStructLevel |
||||
typeStructOnly |
||||
typeDive |
||||
typeOr |
||||
typeKeys |
||||
typeEndKeys |
||||
) |
||||
|
||||
const ( |
||||
invalidValidation = "Invalid validation tag on field '%s'" |
||||
undefinedValidation = "Undefined validation function '%s' on field '%s'" |
||||
keysTagNotDefined = "'" + endKeysTag + "' tag encountered without a corresponding '" + keysTag + "' tag" |
||||
) |
||||
|
||||
type structCache struct { |
||||
lock sync.Mutex |
||||
m atomic.Value // map[reflect.Type]*cStruct
|
||||
} |
||||
|
||||
func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) { |
||||
c, found = sc.m.Load().(map[reflect.Type]*cStruct)[key] |
||||
return |
||||
} |
||||
|
||||
func (sc *structCache) Set(key reflect.Type, value *cStruct) { |
||||
m := sc.m.Load().(map[reflect.Type]*cStruct) |
||||
nm := make(map[reflect.Type]*cStruct, len(m)+1) |
||||
for k, v := range m { |
||||
nm[k] = v |
||||
} |
||||
nm[key] = value |
||||
sc.m.Store(nm) |
||||
} |
||||
|
||||
type tagCache struct { |
||||
lock sync.Mutex |
||||
m atomic.Value // map[string]*cTag
|
||||
} |
||||
|
||||
func (tc *tagCache) Get(key string) (c *cTag, found bool) { |
||||
c, found = tc.m.Load().(map[string]*cTag)[key] |
||||
return |
||||
} |
||||
|
||||
func (tc *tagCache) Set(key string, value *cTag) { |
||||
m := tc.m.Load().(map[string]*cTag) |
||||
nm := make(map[string]*cTag, len(m)+1) |
||||
for k, v := range m { |
||||
nm[k] = v |
||||
} |
||||
nm[key] = value |
||||
tc.m.Store(nm) |
||||
} |
||||
|
||||
type cStruct struct { |
||||
name string |
||||
fields []*cField |
||||
fn StructLevelFuncCtx |
||||
} |
||||
|
||||
type cField struct { |
||||
idx int |
||||
name string |
||||
altName string |
||||
namesEqual bool |
||||
cTags *cTag |
||||
} |
||||
|
||||
type cTag struct { |
||||
tag string |
||||
aliasTag string |
||||
actualAliasTag string |
||||
param string |
||||
keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation
|
||||
next *cTag |
||||
fn FuncCtx |
||||
typeof tagType |
||||
hasTag bool |
||||
hasAlias bool |
||||
hasParam bool // true if parameter used eg. eq= where the equal sign has been set
|
||||
isBlockEnd bool // indicates the current tag represents the last validation in the block
|
||||
runValidationWhenNil bool |
||||
} |
||||
|
||||
func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct { |
||||
v.structCache.lock.Lock() |
||||
defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise!
|
||||
|
||||
typ := current.Type() |
||||
|
||||
// could have been multiple trying to access, but once first is done this ensures struct
|
||||
// isn't parsed again.
|
||||
cs, ok := v.structCache.Get(typ) |
||||
if ok { |
||||
return cs |
||||
} |
||||
|
||||
cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]} |
||||
|
||||
numFields := current.NumField() |
||||
rules := v.rules[typ] |
||||
|
||||
var ctag *cTag |
||||
var fld reflect.StructField |
||||
var tag string |
||||
var customName string |
||||
|
||||
for i := 0; i < numFields; i++ { |
||||
|
||||
fld = typ.Field(i) |
||||
|
||||
if !fld.Anonymous && len(fld.PkgPath) > 0 { |
||||
continue |
||||
} |
||||
|
||||
if rtag, ok := rules[fld.Name]; ok { |
||||
tag = rtag |
||||
} else { |
||||
tag = fld.Tag.Get(v.tagName) |
||||
} |
||||
|
||||
if tag == skipValidationTag { |
||||
continue |
||||
} |
||||
|
||||
customName = fld.Name |
||||
|
||||
if v.hasTagNameFunc { |
||||
name := v.tagNameFunc(fld) |
||||
if len(name) > 0 { |
||||
customName = name |
||||
} |
||||
} |
||||
|
||||
// NOTE: cannot use shared tag cache, because tags may be equal, but things like alias may be different
|
||||
// and so only struct level caching can be used instead of combined with Field tag caching
|
||||
|
||||
if len(tag) > 0 { |
||||
ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false) |
||||
} else { |
||||
// even if field doesn't have validations need cTag for traversing to potential inner/nested
|
||||
// elements of the field.
|
||||
ctag = new(cTag) |
||||
} |
||||
|
||||
cs.fields = append(cs.fields, &cField{ |
||||
idx: i, |
||||
name: fld.Name, |
||||
altName: customName, |
||||
cTags: ctag, |
||||
namesEqual: fld.Name == customName, |
||||
}) |
||||
} |
||||
v.structCache.Set(typ, cs) |
||||
return cs |
||||
} |
||||
|
||||
func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) { |
||||
var t string |
||||
noAlias := len(alias) == 0 |
||||
tags := strings.Split(tag, tagSeparator) |
||||
|
||||
for i := 0; i < len(tags); i++ { |
||||
t = tags[i] |
||||
if noAlias { |
||||
alias = t |
||||
} |
||||
|
||||
// check map for alias and process new tags, otherwise process as usual
|
||||
if tagsVal, found := v.aliases[t]; found { |
||||
if i == 0 { |
||||
firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) |
||||
} else { |
||||
next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) |
||||
current.next, current = next, curr |
||||
|
||||
} |
||||
continue |
||||
} |
||||
|
||||
var prevTag tagType |
||||
|
||||
if i == 0 { |
||||
current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true, typeof: typeDefault} |
||||
firstCtag = current |
||||
} else { |
||||
prevTag = current.typeof |
||||
current.next = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true} |
||||
current = current.next |
||||
} |
||||
|
||||
switch t { |
||||
case diveTag: |
||||
current.typeof = typeDive |
||||
continue |
||||
|
||||
case keysTag: |
||||
current.typeof = typeKeys |
||||
|
||||
if i == 0 || prevTag != typeDive { |
||||
panic(fmt.Sprintf("'%s' tag must be immediately preceded by the '%s' tag", keysTag, diveTag)) |
||||
} |
||||
|
||||
current.typeof = typeKeys |
||||
|
||||
// need to pass along only keys tag
|
||||
// need to increment i to skip over the keys tags
|
||||
b := make([]byte, 0, 64) |
||||
|
||||
i++ |
||||
|
||||
for ; i < len(tags); i++ { |
||||
|
||||
b = append(b, tags[i]...) |
||||
b = append(b, ',') |
||||
|
||||
if tags[i] == endKeysTag { |
||||
break |
||||
} |
||||
} |
||||
|
||||
current.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), fieldName, "", false) |
||||
continue |
||||
|
||||
case endKeysTag: |
||||
current.typeof = typeEndKeys |
||||
|
||||
// if there are more in tags then there was no keysTag defined
|
||||
// and an error should be thrown
|
||||
if i != len(tags)-1 { |
||||
panic(keysTagNotDefined) |
||||
} |
||||
return |
||||
|
||||
case omitempty: |
||||
current.typeof = typeOmitEmpty |
||||
continue |
||||
|
||||
case structOnlyTag: |
||||
current.typeof = typeStructOnly |
||||
continue |
||||
|
||||
case noStructLevelTag: |
||||
current.typeof = typeNoStructLevel |
||||
continue |
||||
|
||||
default: |
||||
if t == isdefault { |
||||
current.typeof = typeIsDefault |
||||
} |
||||
// if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C"
|
||||
orVals := strings.Split(t, orSeparator) |
||||
|
||||
for j := 0; j < len(orVals); j++ { |
||||
vals := strings.SplitN(orVals[j], tagKeySeparator, 2) |
||||
if noAlias { |
||||
alias = vals[0] |
||||
current.aliasTag = alias |
||||
} else { |
||||
current.actualAliasTag = t |
||||
} |
||||
|
||||
if j > 0 { |
||||
current.next = &cTag{aliasTag: alias, actualAliasTag: current.actualAliasTag, hasAlias: hasAlias, hasTag: true} |
||||
current = current.next |
||||
} |
||||
current.hasParam = len(vals) > 1 |
||||
|
||||
current.tag = vals[0] |
||||
if len(current.tag) == 0 { |
||||
panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName))) |
||||
} |
||||
|
||||
if wrapper, ok := v.validations[current.tag]; ok { |
||||
current.fn = wrapper.fn |
||||
current.runValidationWhenNil = wrapper.runValidatinOnNil |
||||
} else { |
||||
panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName))) |
||||
} |
||||
|
||||
if len(orVals) > 1 { |
||||
current.typeof = typeOr |
||||
} |
||||
|
||||
if len(vals) > 1 { |
||||
current.param = strings.Replace(strings.Replace(vals[1], utf8HexComma, ",", -1), utf8Pipe, "|", -1) |
||||
} |
||||
} |
||||
current.isBlockEnd = true |
||||
} |
||||
} |
||||
return |
||||
} |
||||
|
||||
func (v *Validate) fetchCacheTag(tag string) *cTag { |
||||
// find cached tag
|
||||
ctag, found := v.tagCache.Get(tag) |
||||
if !found { |
||||
v.tagCache.lock.Lock() |
||||
defer v.tagCache.lock.Unlock() |
||||
|
||||
// could have been multiple trying to access, but once first is done this ensures tag
|
||||
// isn't parsed again.
|
||||
ctag, found = v.tagCache.Get(tag) |
||||
if !found { |
||||
ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) |
||||
v.tagCache.Set(tag, ctag) |
||||
} |
||||
} |
||||
return ctag |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,79 @@ |
||||
package validator |
||||
|
||||
var iso4217 = map[string]bool{ |
||||
"AFN": true, "EUR": true, "ALL": true, "DZD": true, "USD": true, |
||||
"AOA": true, "XCD": true, "ARS": true, "AMD": true, "AWG": true, |
||||
"AUD": true, "AZN": true, "BSD": true, "BHD": true, "BDT": true, |
||||
"BBD": true, "BYN": true, "BZD": true, "XOF": true, "BMD": true, |
||||
"INR": true, "BTN": true, "BOB": true, "BOV": true, "BAM": true, |
||||
"BWP": true, "NOK": true, "BRL": true, "BND": true, "BGN": true, |
||||
"BIF": true, "CVE": true, "KHR": true, "XAF": true, "CAD": true, |
||||
"KYD": true, "CLP": true, "CLF": true, "CNY": true, "COP": true, |
||||
"COU": true, "KMF": true, "CDF": true, "NZD": true, "CRC": true, |
||||
"HRK": true, "CUP": true, "CUC": true, "ANG": true, "CZK": true, |
||||
"DKK": true, "DJF": true, "DOP": true, "EGP": true, "SVC": true, |
||||
"ERN": true, "SZL": true, "ETB": true, "FKP": true, "FJD": true, |
||||
"XPF": true, "GMD": true, "GEL": true, "GHS": true, "GIP": true, |
||||
"GTQ": true, "GBP": true, "GNF": true, "GYD": true, "HTG": true, |
||||
"HNL": true, "HKD": true, "HUF": true, "ISK": true, "IDR": true, |
||||
"XDR": true, "IRR": true, "IQD": true, "ILS": true, "JMD": true, |
||||
"JPY": true, "JOD": true, "KZT": true, "KES": true, "KPW": true, |
||||
"KRW": true, "KWD": true, "KGS": true, "LAK": true, "LBP": true, |
||||
"LSL": true, "ZAR": true, "LRD": true, "LYD": true, "CHF": true, |
||||
"MOP": true, "MKD": true, "MGA": true, "MWK": true, "MYR": true, |
||||
"MVR": true, "MRU": true, "MUR": true, "XUA": true, "MXN": true, |
||||
"MXV": true, "MDL": true, "MNT": true, "MAD": true, "MZN": true, |
||||
"MMK": true, "NAD": true, "NPR": true, "NIO": true, "NGN": true, |
||||
"OMR": true, "PKR": true, "PAB": true, "PGK": true, "PYG": true, |
||||
"PEN": true, "PHP": true, "PLN": true, "QAR": true, "RON": true, |
||||
"RUB": true, "RWF": true, "SHP": true, "WST": true, "STN": true, |
||||
"SAR": true, "RSD": true, "SCR": true, "SLL": true, "SGD": true, |
||||
"XSU": true, "SBD": true, "SOS": true, "SSP": true, "LKR": true, |
||||
"SDG": true, "SRD": true, "SEK": true, "CHE": true, "CHW": true, |
||||
"SYP": true, "TWD": true, "TJS": true, "TZS": true, "THB": true, |
||||
"TOP": true, "TTD": true, "TND": true, "TRY": true, "TMT": true, |
||||
"UGX": true, "UAH": true, "AED": true, "USN": true, "UYU": true, |
||||
"UYI": true, "UYW": true, "UZS": true, "VUV": true, "VES": true, |
||||
"VND": true, "YER": true, "ZMW": true, "ZWL": true, "XBA": true, |
||||
"XBB": true, "XBC": true, "XBD": true, "XTS": true, "XXX": true, |
||||
"XAU": true, "XPD": true, "XPT": true, "XAG": true, |
||||
} |
||||
|
||||
var iso4217_numeric = map[int]bool{ |
||||
8: true, 12: true, 32: true, 36: true, 44: true, |
||||
48: true, 50: true, 51: true, 52: true, 60: true, |
||||
64: true, 68: true, 72: true, 84: true, 90: true, |
||||
96: true, 104: true, 108: true, 116: true, 124: true, |
||||
132: true, 136: true, 144: true, 152: true, 156: true, |
||||
170: true, 174: true, 188: true, 191: true, 192: true, |
||||
203: true, 208: true, 214: true, 222: true, 230: true, |
||||
232: true, 238: true, 242: true, 262: true, 270: true, |
||||
292: true, 320: true, 324: true, 328: true, 332: true, |
||||
340: true, 344: true, 348: true, 352: true, 356: true, |
||||
360: true, 364: true, 368: true, 376: true, 388: true, |
||||
392: true, 398: true, 400: true, 404: true, 408: true, |
||||
410: true, 414: true, 417: true, 418: true, 422: true, |
||||
426: true, 430: true, 434: true, 446: true, 454: true, |
||||
458: true, 462: true, 480: true, 484: true, 496: true, |
||||
498: true, 504: true, 512: true, 516: true, 524: true, |
||||
532: true, 533: true, 548: true, 554: true, 558: true, |
||||
566: true, 578: true, 586: true, 590: true, 598: true, |
||||
600: true, 604: true, 608: true, 634: true, 643: true, |
||||
646: true, 654: true, 682: true, 690: true, 694: true, |
||||
702: true, 704: true, 706: true, 710: true, 728: true, |
||||
748: true, 752: true, 756: true, 760: true, 764: true, |
||||
776: true, 780: true, 784: true, 788: true, 800: true, |
||||
807: true, 818: true, 826: true, 834: true, 840: true, |
||||
858: true, 860: true, 882: true, 886: true, 901: true, |
||||
927: true, 928: true, 929: true, 930: true, 931: true, |
||||
932: true, 933: true, 934: true, 936: true, 938: true, |
||||
940: true, 941: true, 943: true, 944: true, 946: true, |
||||
947: true, 948: true, 949: true, 950: true, 951: true, |
||||
952: true, 953: true, 955: true, 956: true, 957: true, |
||||
958: true, 959: true, 960: true, 961: true, 962: true, |
||||
963: true, 964: true, 965: true, 967: true, 968: true, |
||||
969: true, 970: true, 971: true, 972: true, 973: true, |
||||
975: true, 976: true, 977: true, 978: true, 979: true, |
||||
980: true, 981: true, 984: true, 985: true, 986: true, |
||||
990: true, 994: true, 997: true, 999: true, |
||||
} |
@ -0,0 +1,272 @@ |
||||
package validator |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"reflect" |
||||
"strings" |
||||
|
||||
ut "github.com/go-playground/universal-translator" |
||||
) |
||||
|
||||
const ( |
||||
fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag" |
||||
) |
||||
|
||||
// ValidationErrorsTranslations is the translation return type
|
||||
type ValidationErrorsTranslations map[string]string |
||||
|
||||
// InvalidValidationError describes an invalid argument passed to
|
||||
// `Struct`, `StructExcept`, StructPartial` or `Field`
|
||||
type InvalidValidationError struct { |
||||
Type reflect.Type |
||||
} |
||||
|
||||
// Error returns InvalidValidationError message
|
||||
func (e *InvalidValidationError) Error() string { |
||||
|
||||
if e.Type == nil { |
||||
return "validator: (nil)" |
||||
} |
||||
|
||||
return "validator: (nil " + e.Type.String() + ")" |
||||
} |
||||
|
||||
// ValidationErrors is an array of FieldError's
|
||||
// for use in custom error messages post validation.
|
||||
type ValidationErrors []FieldError |
||||
|
||||
// Error is intended for use in development + debugging and not intended to be a production error message.
|
||||
// It allows ValidationErrors to subscribe to the Error interface.
|
||||
// All information to create an error message specific to your application is contained within
|
||||
// the FieldError found within the ValidationErrors array
|
||||
func (ve ValidationErrors) Error() string { |
||||
|
||||
buff := bytes.NewBufferString("") |
||||
|
||||
for i := 0; i < len(ve); i++ { |
||||
|
||||
buff.WriteString(ve[i].Error()) |
||||
buff.WriteString("\n") |
||||
} |
||||
|
||||
return strings.TrimSpace(buff.String()) |
||||
} |
||||
|
||||
// Translate translates all of the ValidationErrors
|
||||
func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslations { |
||||
|
||||
trans := make(ValidationErrorsTranslations) |
||||
|
||||
var fe *fieldError |
||||
|
||||
for i := 0; i < len(ve); i++ { |
||||
fe = ve[i].(*fieldError) |
||||
|
||||
// // in case an Anonymous struct was used, ensure that the key
|
||||
// // would be 'Username' instead of ".Username"
|
||||
// if len(fe.ns) > 0 && fe.ns[:1] == "." {
|
||||
// trans[fe.ns[1:]] = fe.Translate(ut)
|
||||
// continue
|
||||
// }
|
||||
|
||||
trans[fe.ns] = fe.Translate(ut) |
||||
} |
||||
|
||||
return trans |
||||
} |
||||
|
||||
// FieldError contains all functions to get error details
|
||||
type FieldError interface { |
||||
|
||||
// Tag returns the validation tag that failed. if the
|
||||
// validation was an alias, this will return the
|
||||
// alias name and not the underlying tag that failed.
|
||||
//
|
||||
// eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla"
|
||||
// will return "iscolor"
|
||||
Tag() string |
||||
|
||||
// ActualTag returns the validation tag that failed, even if an
|
||||
// alias the actual tag within the alias will be returned.
|
||||
// If an 'or' validation fails the entire or will be returned.
|
||||
//
|
||||
// eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla"
|
||||
// will return "hexcolor|rgb|rgba|hsl|hsla"
|
||||
ActualTag() string |
||||
|
||||
// Namespace returns the namespace for the field error, with the tag
|
||||
// name taking precedence over the field's actual name.
|
||||
//
|
||||
// eg. JSON name "User.fname"
|
||||
//
|
||||
// See StructNamespace() for a version that returns actual names.
|
||||
//
|
||||
// NOTE: this field can be blank when validating a single primitive field
|
||||
// using validate.Field(...) as there is no way to extract it's name
|
||||
Namespace() string |
||||
|
||||
// StructNamespace returns the namespace for the field error, with the field's
|
||||
// actual name.
|
||||
//
|
||||
// eq. "User.FirstName" see Namespace for comparison
|
||||
//
|
||||
// NOTE: this field can be blank when validating a single primitive field
|
||||
// using validate.Field(...) as there is no way to extract its name
|
||||
StructNamespace() string |
||||
|
||||
// Field returns the fields name with the tag name taking precedence over the
|
||||
// field's actual name.
|
||||
//
|
||||
// eq. JSON name "fname"
|
||||
// see StructField for comparison
|
||||
Field() string |
||||
|
||||
// StructField returns the field's actual name from the struct, when able to determine.
|
||||
//
|
||||
// eq. "FirstName"
|
||||
// see Field for comparison
|
||||
StructField() string |
||||
|
||||
// Value returns the actual field's value in case needed for creating the error
|
||||
// message
|
||||
Value() interface{} |
||||
|
||||
// Param returns the param value, in string form for comparison; this will also
|
||||
// help with generating an error message
|
||||
Param() string |
||||
|
||||
// Kind returns the Field's reflect Kind
|
||||
//
|
||||
// eg. time.Time's kind is a struct
|
||||
Kind() reflect.Kind |
||||
|
||||
// Type returns the Field's reflect Type
|
||||
//
|
||||
// eg. time.Time's type is time.Time
|
||||
Type() reflect.Type |
||||
|
||||
// Translate returns the FieldError's translated error
|
||||
// from the provided 'ut.Translator' and registered 'TranslationFunc'
|
||||
//
|
||||
// NOTE: if no registered translator can be found it returns the same as
|
||||
// calling fe.Error()
|
||||
Translate(ut ut.Translator) string |
||||
|
||||
// Error returns the FieldError's message
|
||||
Error() string |
||||
} |
||||
|
||||
// compile time interface checks
|
||||
var _ FieldError = new(fieldError) |
||||
var _ error = new(fieldError) |
||||
|
||||
// fieldError contains a single field's validation error along
|
||||
// with other properties that may be needed for error message creation
|
||||
// it complies with the FieldError interface
|
||||
type fieldError struct { |
||||
v *Validate |
||||
tag string |
||||
actualTag string |
||||
ns string |
||||
structNs string |
||||
fieldLen uint8 |
||||
structfieldLen uint8 |
||||
value interface{} |
||||
param string |
||||
kind reflect.Kind |
||||
typ reflect.Type |
||||
} |
||||
|
||||
// Tag returns the validation tag that failed.
|
||||
func (fe *fieldError) Tag() string { |
||||
return fe.tag |
||||
} |
||||
|
||||
// ActualTag returns the validation tag that failed, even if an
|
||||
// alias the actual tag within the alias will be returned.
|
||||
func (fe *fieldError) ActualTag() string { |
||||
return fe.actualTag |
||||
} |
||||
|
||||
// Namespace returns the namespace for the field error, with the tag
|
||||
// name taking precedence over the field's actual name.
|
||||
func (fe *fieldError) Namespace() string { |
||||
return fe.ns |
||||
} |
||||
|
||||
// StructNamespace returns the namespace for the field error, with the field's
|
||||
// actual name.
|
||||
func (fe *fieldError) StructNamespace() string { |
||||
return fe.structNs |
||||
} |
||||
|
||||
// Field returns the field's name with the tag name taking precedence over the
|
||||
// field's actual name.
|
||||
func (fe *fieldError) Field() string { |
||||
|
||||
return fe.ns[len(fe.ns)-int(fe.fieldLen):] |
||||
// // return fe.field
|
||||
// fld := fe.ns[len(fe.ns)-int(fe.fieldLen):]
|
||||
|
||||
// log.Println("FLD:", fld)
|
||||
|
||||
// if len(fld) > 0 && fld[:1] == "." {
|
||||
// return fld[1:]
|
||||
// }
|
||||
|
||||
// return fld
|
||||
} |
||||
|
||||
// StructField returns the field's actual name from the struct, when able to determine.
|
||||
func (fe *fieldError) StructField() string { |
||||
// return fe.structField
|
||||
return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):] |
||||
} |
||||
|
||||
// Value returns the actual field's value in case needed for creating the error
|
||||
// message
|
||||
func (fe *fieldError) Value() interface{} { |
||||
return fe.value |
||||
} |
||||
|
||||
// Param returns the param value, in string form for comparison; this will
|
||||
// also help with generating an error message
|
||||
func (fe *fieldError) Param() string { |
||||
return fe.param |
||||
} |
||||
|
||||
// Kind returns the Field's reflect Kind
|
||||
func (fe *fieldError) Kind() reflect.Kind { |
||||
return fe.kind |
||||
} |
||||
|
||||
// Type returns the Field's reflect Type
|
||||
func (fe *fieldError) Type() reflect.Type { |
||||
return fe.typ |
||||
} |
||||
|
||||
// Error returns the fieldError's error message
|
||||
func (fe *fieldError) Error() string { |
||||
return fmt.Sprintf(fieldErrMsg, fe.ns, fe.Field(), fe.tag) |
||||
} |
||||
|
||||
// Translate returns the FieldError's translated error
|
||||
// from the provided 'ut.Translator' and registered 'TranslationFunc'
|
||||
//
|
||||
// NOTE: if no registered translation can be found, it returns the original
|
||||
// untranslated error message.
|
||||
func (fe *fieldError) Translate(ut ut.Translator) string { |
||||
|
||||
m, ok := fe.v.transTagFunc[ut] |
||||
if !ok { |
||||
return fe.Error() |
||||
} |
||||
|
||||
fn, ok := m[fe.tag] |
||||
if !ok { |
||||
return fe.Error() |
||||
} |
||||
|
||||
return fn(ut, fe) |
||||
} |
@ -0,0 +1,120 @@ |
||||
package validator |
||||
|
||||
import "reflect" |
||||
|
||||
// FieldLevel contains all the information and helper functions
|
||||
// to validate a field
|
||||
type FieldLevel interface { |
||||
|
||||
// Top returns the top level struct, if any
|
||||
Top() reflect.Value |
||||
|
||||
// Parent returns the current fields parent struct, if any or
|
||||
// the comparison value if called 'VarWithValue'
|
||||
Parent() reflect.Value |
||||
|
||||
// Field returns current field for validation
|
||||
Field() reflect.Value |
||||
|
||||
// FieldName returns the field's name with the tag
|
||||
// name taking precedence over the fields actual name.
|
||||
FieldName() string |
||||
|
||||
// StructFieldName returns the struct field's name
|
||||
StructFieldName() string |
||||
|
||||
// Param returns param for validation against current field
|
||||
Param() string |
||||
|
||||
// GetTag returns the current validations tag name
|
||||
GetTag() string |
||||
|
||||
// ExtractType gets the actual underlying type of field value.
|
||||
// It will dive into pointers, customTypes and return you the
|
||||
// underlying value and it's kind.
|
||||
ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) |
||||
|
||||
// GetStructFieldOK traverses the parent struct to retrieve a specific field denoted by the provided namespace
|
||||
// in the param and returns the field, field kind and whether is was successful in retrieving
|
||||
// the field at all.
|
||||
//
|
||||
// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
|
||||
// could not be retrieved because it didn't exist.
|
||||
//
|
||||
// Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable.
|
||||
GetStructFieldOK() (reflect.Value, reflect.Kind, bool) |
||||
|
||||
// GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for
|
||||
// the field and namespace allowing more extensibility for validators.
|
||||
//
|
||||
// Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable.
|
||||
GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) |
||||
|
||||
// GetStructFieldOK2 traverses the parent struct to retrieve a specific field denoted by the provided namespace
|
||||
// in the param and returns the field, field kind, if it's a nullable type and whether is was successful in retrieving
|
||||
// the field at all.
|
||||
//
|
||||
// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
|
||||
// could not be retrieved because it didn't exist.
|
||||
GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) |
||||
|
||||
// GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for
|
||||
// the field and namespace allowing more extensibility for validators.
|
||||
GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) |
||||
} |
||||
|
||||
var _ FieldLevel = new(validate) |
||||
|
||||
// Field returns current field for validation
|
||||
func (v *validate) Field() reflect.Value { |
||||
return v.flField |
||||
} |
||||
|
||||
// FieldName returns the field's name with the tag
|
||||
// name taking precedence over the fields actual name.
|
||||
func (v *validate) FieldName() string { |
||||
return v.cf.altName |
||||
} |
||||
|
||||
// GetTag returns the current validations tag name
|
||||
func (v *validate) GetTag() string { |
||||
return v.ct.tag |
||||
} |
||||
|
||||
// StructFieldName returns the struct field's name
|
||||
func (v *validate) StructFieldName() string { |
||||
return v.cf.name |
||||
} |
||||
|
||||
// Param returns param for validation against current field
|
||||
func (v *validate) Param() string { |
||||
return v.ct.param |
||||
} |
||||
|
||||
// GetStructFieldOK returns Param returns param for validation against current field
|
||||
//
|
||||
// Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable.
|
||||
func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) { |
||||
current, kind, _, found := v.getStructFieldOKInternal(v.slflParent, v.ct.param) |
||||
return current, kind, found |
||||
} |
||||
|
||||
// GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for
|
||||
// the field and namespace allowing more extensibility for validators.
|
||||
//
|
||||
// Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable.
|
||||
func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { |
||||
current, kind, _, found := v.GetStructFieldOKAdvanced2(val, namespace) |
||||
return current, kind, found |
||||
} |
||||
|
||||
// GetStructFieldOK2 returns Param returns param for validation against current field
|
||||
func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) { |
||||
return v.getStructFieldOKInternal(v.slflParent, v.ct.param) |
||||
} |
||||
|
||||
// GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for
|
||||
// the field and namespace allowing more extensibility for validators.
|
||||
func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) { |
||||
return v.getStructFieldOKInternal(val, namespace) |
||||
} |
@ -0,0 +1,14 @@ |
||||
module github.com/go-playground/validator/v10 |
||||
|
||||
go 1.18 |
||||
|
||||
require ( |
||||
github.com/go-playground/assert/v2 v2.2.0 |
||||
github.com/go-playground/locales v0.14.1 |
||||
github.com/go-playground/universal-translator v0.18.1 |
||||
github.com/leodido/go-urn v1.2.2 |
||||
golang.org/x/crypto v0.7.0 |
||||
golang.org/x/text v0.8.0 |
||||
) |
||||
|
||||
require golang.org/x/sys v0.6.0 // indirect |
@ -0,0 +1,31 @@ |
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= |
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= |
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= |
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= |
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= |
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= |
||||
github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4= |
||||
github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ= |
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
||||
github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ= |
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= |
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= |
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= |
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= |
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= |
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= |
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= |
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= |
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= |
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= |
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= |
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
@ -0,0 +1,25 @@ |
||||
package validators |
||||
|
||||
import ( |
||||
"reflect" |
||||
"strings" |
||||
|
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
// NotBlank is the validation function for validating if the current field
|
||||
// has a value or length greater than zero, or is not a space only string.
|
||||
func NotBlank(fl validator.FieldLevel) bool { |
||||
field := fl.Field() |
||||
|
||||
switch field.Kind() { |
||||
case reflect.String: |
||||
return len(strings.Trim(strings.TrimSpace(field.String()), "\x1c\x1d\x1e\x1f")) > 0 |
||||
case reflect.Chan, reflect.Map, reflect.Slice, reflect.Array: |
||||
return field.Len() > 0 |
||||
case reflect.Ptr, reflect.Interface, reflect.Func: |
||||
return !field.IsNil() |
||||
default: |
||||
return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() |
||||
} |
||||
} |
@ -0,0 +1,65 @@ |
||||
package validators |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"github.com/go-playground/assert/v2" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
type test struct { |
||||
String string `validate:"notblank"` |
||||
Array []int `validate:"notblank"` |
||||
Pointer *int `validate:"notblank"` |
||||
Number int `validate:"notblank"` |
||||
Interface interface{} `validate:"notblank"` |
||||
Func func() `validate:"notblank"` |
||||
} |
||||
|
||||
func TestNotBlank(t *testing.T) { |
||||
v := validator.New() |
||||
err := v.RegisterValidation("notblank", NotBlank) |
||||
assert.Equal(t, nil, err) |
||||
|
||||
// Errors
|
||||
var x *int |
||||
invalid := test{ |
||||
String: " \x1c\x1d\x1e\x1f\r\n", |
||||
Array: []int{}, |
||||
Pointer: x, |
||||
Number: 0, |
||||
Interface: nil, |
||||
Func: nil, |
||||
} |
||||
fieldsWithError := []string{ |
||||
"String", |
||||
"Array", |
||||
"Pointer", |
||||
"Number", |
||||
"Interface", |
||||
"Func", |
||||
} |
||||
|
||||
errors := v.Struct(invalid).(validator.ValidationErrors) |
||||
var fields []string |
||||
for _, err := range errors { |
||||
fields = append(fields, err.Field()) |
||||
} |
||||
|
||||
assert.Equal(t, fieldsWithError, fields) |
||||
|
||||
// No errors
|
||||
y := 1 |
||||
x = &y |
||||
valid := test{ |
||||
String: "str", |
||||
Array: []int{1}, |
||||
Pointer: x, |
||||
Number: 1, |
||||
Interface: "value", |
||||
Func: func() {}, |
||||
} |
||||
|
||||
err = v.Struct(valid) |
||||
assert.Equal(t, nil, err) |
||||
} |
@ -0,0 +1,173 @@ |
||||
package validator |
||||
|
||||
import "regexp" |
||||
|
||||
var postCodePatternDict = map[string]string{ |
||||
"GB": `^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}$`, |
||||
"JE": `^JE\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, |
||||
"GG": `^GY\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, |
||||
"IM": `^IM\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, |
||||
"US": `^\d{5}([ \-]\d{4})?$`, |
||||
"CA": `^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ ]?\d[ABCEGHJ-NPRSTV-Z]\d$`, |
||||
"DE": `^\d{5}$`, |
||||
"JP": `^\d{3}-\d{4}$`, |
||||
"FR": `^\d{2}[ ]?\d{3}$`, |
||||
"AU": `^\d{4}$`, |
||||
"IT": `^\d{5}$`, |
||||
"CH": `^\d{4}$`, |
||||
"AT": `^\d{4}$`, |
||||
"ES": `^\d{5}$`, |
||||
"NL": `^\d{4}[ ]?[A-Z]{2}$`, |
||||
"BE": `^\d{4}$`, |
||||
"DK": `^\d{4}$`, |
||||
"SE": `^\d{3}[ ]?\d{2}$`, |
||||
"NO": `^\d{4}$`, |
||||
"BR": `^\d{5}[\-]?\d{3}$`, |
||||
"PT": `^\d{4}([\-]\d{3})?$`, |
||||
"FI": `^\d{5}$`, |
||||
"AX": `^22\d{3}$`, |
||||
"KR": `^\d{3}[\-]\d{3}$`, |
||||
"CN": `^\d{6}$`, |
||||
"TW": `^\d{3}(\d{2})?$`, |
||||
"SG": `^\d{6}$`, |
||||
"DZ": `^\d{5}$`, |
||||
"AD": `^AD\d{3}$`, |
||||
"AR": `^([A-HJ-NP-Z])?\d{4}([A-Z]{3})?$`, |
||||
"AM": `^(37)?\d{4}$`, |
||||
"AZ": `^\d{4}$`, |
||||
"BH": `^((1[0-2]|[2-9])\d{2})?$`, |
||||
"BD": `^\d{4}$`, |
||||
"BB": `^(BB\d{5})?$`, |
||||
"BY": `^\d{6}$`, |
||||
"BM": `^[A-Z]{2}[ ]?[A-Z0-9]{2}$`, |
||||
"BA": `^\d{5}$`, |
||||
"IO": `^BBND 1ZZ$`, |
||||
"BN": `^[A-Z]{2}[ ]?\d{4}$`, |
||||
"BG": `^\d{4}$`, |
||||
"KH": `^\d{5}$`, |
||||
"CV": `^\d{4}$`, |
||||
"CL": `^\d{7}$`, |
||||
"CR": `^\d{4,5}|\d{3}-\d{4}$`, |
||||
"HR": `^\d{5}$`, |
||||
"CY": `^\d{4}$`, |
||||
"CZ": `^\d{3}[ ]?\d{2}$`, |
||||
"DO": `^\d{5}$`, |
||||
"EC": `^([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?$`, |
||||
"EG": `^\d{5}$`, |
||||
"EE": `^\d{5}$`, |
||||
"FO": `^\d{3}$`, |
||||
"GE": `^\d{4}$`, |
||||
"GR": `^\d{3}[ ]?\d{2}$`, |
||||
"GL": `^39\d{2}$`, |
||||
"GT": `^\d{5}$`, |
||||
"HT": `^\d{4}$`, |
||||
"HN": `^(?:\d{5})?$`, |
||||
"HU": `^\d{4}$`, |
||||
"IS": `^\d{3}$`, |
||||
"IN": `^\d{6}$`, |
||||
"ID": `^\d{5}$`, |
||||
"IL": `^\d{5}$`, |
||||
"JO": `^\d{5}$`, |
||||
"KZ": `^\d{6}$`, |
||||
"KE": `^\d{5}$`, |
||||
"KW": `^\d{5}$`, |
||||
"LA": `^\d{5}$`, |
||||
"LV": `^\d{4}$`, |
||||
"LB": `^(\d{4}([ ]?\d{4})?)?$`, |
||||
"LI": `^(948[5-9])|(949[0-7])$`, |
||||
"LT": `^\d{5}$`, |
||||
"LU": `^\d{4}$`, |
||||
"MK": `^\d{4}$`, |
||||
"MY": `^\d{5}$`, |
||||
"MV": `^\d{5}$`, |
||||
"MT": `^[A-Z]{3}[ ]?\d{2,4}$`, |
||||
"MU": `^(\d{3}[A-Z]{2}\d{3})?$`, |
||||
"MX": `^\d{5}$`, |
||||
"MD": `^\d{4}$`, |
||||
"MC": `^980\d{2}$`, |
||||
"MA": `^\d{5}$`, |
||||
"NP": `^\d{5}$`, |
||||
"NZ": `^\d{4}$`, |
||||
"NI": `^((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?$`, |
||||
"NG": `^(\d{6})?$`, |
||||
"OM": `^(PC )?\d{3}$`, |
||||
"PK": `^\d{5}$`, |
||||
"PY": `^\d{4}$`, |
||||
"PH": `^\d{4}$`, |
||||
"PL": `^\d{2}-\d{3}$`, |
||||
"PR": `^00[679]\d{2}([ \-]\d{4})?$`, |
||||
"RO": `^\d{6}$`, |
||||
"RU": `^\d{6}$`, |
||||
"SM": `^4789\d$`, |
||||
"SA": `^\d{5}$`, |
||||
"SN": `^\d{5}$`, |
||||
"SK": `^\d{3}[ ]?\d{2}$`, |
||||
"SI": `^\d{4}$`, |
||||
"ZA": `^\d{4}$`, |
||||
"LK": `^\d{5}$`, |
||||
"TJ": `^\d{6}$`, |
||||
"TH": `^\d{5}$`, |
||||
"TN": `^\d{4}$`, |
||||
"TR": `^\d{5}$`, |
||||
"TM": `^\d{6}$`, |
||||
"UA": `^\d{5}$`, |
||||
"UY": `^\d{5}$`, |
||||
"UZ": `^\d{6}$`, |
||||
"VA": `^00120$`, |
||||
"VE": `^\d{4}$`, |
||||
"ZM": `^\d{5}$`, |
||||
"AS": `^96799$`, |
||||
"CC": `^6799$`, |
||||
"CK": `^\d{4}$`, |
||||
"RS": `^\d{6}$`, |
||||
"ME": `^8\d{4}$`, |
||||
"CS": `^\d{5}$`, |
||||
"YU": `^\d{5}$`, |
||||
"CX": `^6798$`, |
||||
"ET": `^\d{4}$`, |
||||
"FK": `^FIQQ 1ZZ$`, |
||||
"NF": `^2899$`, |
||||
"FM": `^(9694[1-4])([ \-]\d{4})?$`, |
||||
"GF": `^9[78]3\d{2}$`, |
||||
"GN": `^\d{3}$`, |
||||
"GP": `^9[78][01]\d{2}$`, |
||||
"GS": `^SIQQ 1ZZ$`, |
||||
"GU": `^969[123]\d([ \-]\d{4})?$`, |
||||
"GW": `^\d{4}$`, |
||||
"HM": `^\d{4}$`, |
||||
"IQ": `^\d{5}$`, |
||||
"KG": `^\d{6}$`, |
||||
"LR": `^\d{4}$`, |
||||
"LS": `^\d{3}$`, |
||||
"MG": `^\d{3}$`, |
||||
"MH": `^969[67]\d([ \-]\d{4})?$`, |
||||
"MN": `^\d{6}$`, |
||||
"MP": `^9695[012]([ \-]\d{4})?$`, |
||||
"MQ": `^9[78]2\d{2}$`, |
||||
"NC": `^988\d{2}$`, |
||||
"NE": `^\d{4}$`, |
||||
"VI": `^008(([0-4]\d)|(5[01]))([ \-]\d{4})?$`, |
||||
"VN": `^[0-9]{1,6}$`, |
||||
"PF": `^987\d{2}$`, |
||||
"PG": `^\d{3}$`, |
||||
"PM": `^9[78]5\d{2}$`, |
||||
"PN": `^PCRN 1ZZ$`, |
||||
"PW": `^96940$`, |
||||
"RE": `^9[78]4\d{2}$`, |
||||
"SH": `^(ASCN|STHL) 1ZZ$`, |
||||
"SJ": `^\d{4}$`, |
||||
"SO": `^\d{5}$`, |
||||
"SZ": `^[HLMS]\d{3}$`, |
||||
"TC": `^TKCA 1ZZ$`, |
||||
"WF": `^986\d{2}$`, |
||||
"XK": `^\d{5}$`, |
||||
"YT": `^976\d{2}$`, |
||||
} |
||||
|
||||
var postCodeRegexDict = map[string]*regexp.Regexp{} |
||||
|
||||
func init() { |
||||
for countryCode, pattern := range postCodePatternDict { |
||||
postCodeRegexDict[countryCode] = regexp.MustCompile(pattern) |
||||
} |
||||
} |
@ -0,0 +1,175 @@ |
||||
package validator |
||||
|
||||
import ( |
||||
"context" |
||||
"reflect" |
||||
) |
||||
|
||||
// StructLevelFunc accepts all values needed for struct level validation
|
||||
type StructLevelFunc func(sl StructLevel) |
||||
|
||||
// StructLevelFuncCtx accepts all values needed for struct level validation
|
||||
// but also allows passing of contextual validation information via context.Context.
|
||||
type StructLevelFuncCtx func(ctx context.Context, sl StructLevel) |
||||
|
||||
// wrapStructLevelFunc wraps normal StructLevelFunc makes it compatible with StructLevelFuncCtx
|
||||
func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx { |
||||
return func(ctx context.Context, sl StructLevel) { |
||||
fn(sl) |
||||
} |
||||
} |
||||
|
||||
// StructLevel contains all the information and helper functions
|
||||
// to validate a struct
|
||||
type StructLevel interface { |
||||
|
||||
// Validator returns the main validation object, in case one wants to call validations internally.
|
||||
// this is so you don't have to use anonymous functions to get access to the validate
|
||||
// instance.
|
||||
Validator() *Validate |
||||
|
||||
// Top returns the top level struct, if any
|
||||
Top() reflect.Value |
||||
|
||||
// Parent returns the current fields parent struct, if any
|
||||
Parent() reflect.Value |
||||
|
||||
// Current returns the current struct.
|
||||
Current() reflect.Value |
||||
|
||||
// ExtractType gets the actual underlying type of field value.
|
||||
// It will dive into pointers, customTypes and return you the
|
||||
// underlying value and its kind.
|
||||
ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) |
||||
|
||||
// ReportError reports an error just by passing the field and tag information
|
||||
//
|
||||
// NOTES:
|
||||
//
|
||||
// fieldName and altName get appended to the existing namespace that
|
||||
// validator is on. e.g. pass 'FirstName' or 'Names[0]' depending
|
||||
// on the nesting
|
||||
//
|
||||
// tag can be an existing validation tag or just something you make up
|
||||
// and process on the flip side it's up to you.
|
||||
ReportError(field interface{}, fieldName, structFieldName string, tag, param string) |
||||
|
||||
// ReportValidationErrors reports an error just by passing ValidationErrors
|
||||
//
|
||||
// NOTES:
|
||||
//
|
||||
// relativeNamespace and relativeActualNamespace get appended to the
|
||||
// existing namespace that validator is on.
|
||||
// e.g. pass 'User.FirstName' or 'Users[0].FirstName' depending
|
||||
// on the nesting. most of the time they will be blank, unless you validate
|
||||
// at a level lower the the current field depth
|
||||
ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors) |
||||
} |
||||
|
||||
var _ StructLevel = new(validate) |
||||
|
||||
// Top returns the top level struct
|
||||
//
|
||||
// NOTE: this can be the same as the current struct being validated
|
||||
// if not is a nested struct.
|
||||
//
|
||||
// this is only called when within Struct and Field Level validation and
|
||||
// should not be relied upon for an acurate value otherwise.
|
||||
func (v *validate) Top() reflect.Value { |
||||
return v.top |
||||
} |
||||
|
||||
// Parent returns the current structs parent
|
||||
//
|
||||
// NOTE: this can be the same as the current struct being validated
|
||||
// if not is a nested struct.
|
||||
//
|
||||
// this is only called when within Struct and Field Level validation and
|
||||
// should not be relied upon for an acurate value otherwise.
|
||||
func (v *validate) Parent() reflect.Value { |
||||
return v.slflParent |
||||
} |
||||
|
||||
// Current returns the current struct.
|
||||
func (v *validate) Current() reflect.Value { |
||||
return v.slCurrent |
||||
} |
||||
|
||||
// Validator returns the main validation object, in case one want to call validations internally.
|
||||
func (v *validate) Validator() *Validate { |
||||
return v.v |
||||
} |
||||
|
||||
// ExtractType gets the actual underlying type of field value.
|
||||
func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) { |
||||
return v.extractTypeInternal(field, false) |
||||
} |
||||
|
||||
// ReportError reports an error just by passing the field and tag information
|
||||
func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) { |
||||
|
||||
fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false) |
||||
|
||||
if len(structFieldName) == 0 { |
||||
structFieldName = fieldName |
||||
} |
||||
|
||||
v.str1 = string(append(v.ns, fieldName...)) |
||||
|
||||
if v.v.hasTagNameFunc || fieldName != structFieldName { |
||||
v.str2 = string(append(v.actualNs, structFieldName...)) |
||||
} else { |
||||
v.str2 = v.str1 |
||||
} |
||||
|
||||
if kind == reflect.Invalid { |
||||
|
||||
v.errs = append(v.errs, |
||||
&fieldError{ |
||||
v: v.v, |
||||
tag: tag, |
||||
actualTag: tag, |
||||
ns: v.str1, |
||||
structNs: v.str2, |
||||
fieldLen: uint8(len(fieldName)), |
||||
structfieldLen: uint8(len(structFieldName)), |
||||
param: param, |
||||
kind: kind, |
||||
}, |
||||
) |
||||
return |
||||
} |
||||
|
||||
v.errs = append(v.errs, |
||||
&fieldError{ |
||||
v: v.v, |
||||
tag: tag, |
||||
actualTag: tag, |
||||
ns: v.str1, |
||||
structNs: v.str2, |
||||
fieldLen: uint8(len(fieldName)), |
||||
structfieldLen: uint8(len(structFieldName)), |
||||
value: fv.Interface(), |
||||
param: param, |
||||
kind: kind, |
||||
typ: fv.Type(), |
||||
}, |
||||
) |
||||
} |
||||
|
||||
// ReportValidationErrors reports ValidationErrors obtained from running validations within the Struct Level validation.
|
||||
//
|
||||
// NOTE: this function prepends the current namespace to the relative ones.
|
||||
func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) { |
||||
|
||||
var err *fieldError |
||||
|
||||
for i := 0; i < len(errs); i++ { |
||||
|
||||
err = errs[i].(*fieldError) |
||||
err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...)) |
||||
err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...)) |
||||
|
||||
v.errs = append(v.errs, err) |
||||
} |
||||
} |
@ -0,0 +1 @@ |
||||
package testdata |
@ -0,0 +1,11 @@ |
||||
package validator |
||||
|
||||
import ut "github.com/go-playground/universal-translator" |
||||
|
||||
// TranslationFunc is the function type used to register or override
|
||||
// custom translations
|
||||
type TranslationFunc func(ut ut.Translator, fe FieldError) string |
||||
|
||||
// RegisterTranslationsFunc allows for registering of translations
|
||||
// for a 'ut.Translator' for use within the 'TranslationFunc'
|
||||
type RegisterTranslationsFunc func(ut ut.Translator) error |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,720 @@ |
||||
package en |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
english "github.com/go-playground/locales/en" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
eng := english.New() |
||||
uni := ut.New(eng, eng) |
||||
trans, _ := uni.GetTranslator("en") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
RequiredIf string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
FQDN string `validate:"fqdn"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
UniqueSlice []string `validate:"unique"` |
||||
UniqueArray [3]string `validate:"unique"` |
||||
UniqueMap map[string]string `validate:"unique"` |
||||
JSONString string `validate:"json"` |
||||
JWTString string `validate:"jwt"` |
||||
LowercaseString string `validate:"lowercase"` |
||||
UppercaseString string `validate:"uppercase"` |
||||
Datetime string `validate:"datetime=2006-01-02"` |
||||
PostCode string `validate:"postcode_iso3166_alpha2=SG"` |
||||
PostCodeCountry string |
||||
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` |
||||
BooleanString string `validate:"boolean"` |
||||
CveString string `validate:"cve"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
test.LowercaseString = "ABCDEFG" |
||||
test.UppercaseString = "abcdefg" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
test.UniqueSlice = []string{"1234", "1234"} |
||||
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} |
||||
test.Datetime = "2008-Feb-01" |
||||
test.BooleanString = "A" |
||||
test.CveString = "A" |
||||
|
||||
test.Inner.RequiredIf = "abcd" |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor must be a valid color", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC must contain a valid MAC address", |
||||
}, |
||||
{ |
||||
ns: "Test.FQDN", |
||||
expected: "FQDN must be a valid FQDN", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr must be a resolvable IP address", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4 must be a resolvable IPv4 address", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6 must be a resolvable IPv6 address", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr must be a valid UDP address", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4 must be a valid IPv4 UDP address", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6 must be a valid IPv6 UDP address", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr must be a valid TCP address", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4 must be a valid IPv4 TCP address", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6 must be a valid IPv6 TCP address", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR must contain a valid CIDR notation", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4 must contain a valid CIDR notation for an IPv4 address", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6 must contain a valid CIDR notation for an IPv6 address", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN must be a valid SSN number", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP must be a valid IP address", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4 must be a valid IPv4 address", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6 must be a valid IPv6 address", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI must contain a valid Data URI", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude must contain valid latitude coordinates", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude must contain a valid longitude coordinates", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte must contain multibyte characters", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII must contain only ascii characters", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII must contain only printable ascii characters", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID must be a valid UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3 must be a valid version 3 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4 must be a valid version 4 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5 must be a valid version 5 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID must be a valid ULID", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN must be a valid ISBN number", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10 must be a valid ISBN-10 number", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13 must be a valid ISBN-13 number", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes cannot contain the text 'text'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll cannot contain any of the following characters '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune cannot contain the following '☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny must contain at least one of the following characters '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains must contain the text 'purpose'", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64 must be a valid Base64 string", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email must be a valid email address", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL must be a valid URL", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI must be a valid URI", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString must be a valid RGB color", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString must be a valid RGBA color", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString must be a valid HSL color", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString must be a valid HSLA color", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString must be a valid hexadecimal", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString must be a valid HEX color", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString must be a valid number", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString must be a valid numeric value", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString can only contain alphanumeric characters", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString can only contain alphabetic characters", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString must be less than MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString must be less than or equal to MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString must be greater than MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString must be greater than or equal to MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString cannot be equal to EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString must be less than Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString must be less than or equal to Inner.LteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString must be greater than Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString must be greater than or equal to Inner.GteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString cannot be equal to Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString must be equal to Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString must be equal to MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString must be at least 3 characters in length", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber must be 5.56 or greater", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple must contain at least 2 items", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime must be greater than or equal to the current Date & Time", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString must be greater than 3 characters in length", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber must be greater than 5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple must contain more than 2 items", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime must be greater than the current Date & Time", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString must be at maximum 3 characters in length", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber must be 5.56 or less", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple must contain at maximum 2 items", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime must be less than or equal to the current Date & Time", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString must be less than 3 characters in length", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber must be less than 5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple must contain less than 2 items", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime must be less than the current Date & Time", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString should not be equal to ", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber should not be equal to 0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple should not be equal to 0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString is not equal to 3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber is not equal to 2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple is not equal to 7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString must be a maximum of 3 characters in length", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber must be 1,113.00 or less", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple must contain at maximum 7 items", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString must be at least 1 character in length", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber must be 1,113.00 or greater", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple must contain at least 7 items", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString must be 1 character in length", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber must be equal to 1,113.00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple must contain 7 items", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString is a required field", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredIf", |
||||
expected: "RequiredIf is a required field", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber is a required field", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple is a required field", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen must be at least 10 characters in length", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen must be a maximum of 1 character in length", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen must be 2 characters in length", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt must be less than 1 character in length", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte must be at maximum 1 character in length", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt must be greater than 10 characters in length", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte must be at least 10 characters in length", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString must be one of [red green]", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt must be one of [5 63]", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueSlice", |
||||
expected: "UniqueSlice must contain unique values", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueArray", |
||||
expected: "UniqueArray must contain unique values", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueMap", |
||||
expected: "UniqueMap must contain unique values", |
||||
}, |
||||
{ |
||||
ns: "Test.JSONString", |
||||
expected: "JSONString must be a valid json string", |
||||
}, |
||||
{ |
||||
ns: "Test.JWTString", |
||||
expected: "JWTString must be a valid jwt string", |
||||
}, |
||||
{ |
||||
ns: "Test.LowercaseString", |
||||
expected: "LowercaseString must be a lowercase string", |
||||
}, |
||||
{ |
||||
ns: "Test.UppercaseString", |
||||
expected: "UppercaseString must be an uppercase string", |
||||
}, |
||||
{ |
||||
ns: "Test.Datetime", |
||||
expected: "Datetime does not match the 2006-01-02 format", |
||||
}, |
||||
{ |
||||
ns: "Test.PostCode", |
||||
expected: "PostCode does not match postcode format of SG country", |
||||
}, |
||||
{ |
||||
ns: "Test.PostCodeByField", |
||||
expected: "PostCodeByField does not match postcode format of country in PostCodeCountry field", |
||||
}, |
||||
{ |
||||
ns: "Test.BooleanString", |
||||
expected: "BooleanString must be a valid boolean value", |
||||
}, |
||||
{ |
||||
ns: "Test.CveString", |
||||
expected: "CveString must be a valid cve identifier", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,658 @@ |
||||
package es |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
spanish "github.com/go-playground/locales/es" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
|
||||
spa := spanish.New() |
||||
uni := ut.New(spa, spa) |
||||
trans, _ := uni.GetTranslator("es") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
UniqueSlice []string `validate:"unique"` |
||||
UniqueArray [3]string `validate:"unique"` |
||||
UniqueMap map[string]string `validate:"unique"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
test.UniqueSlice = []string{"1234", "1234"} |
||||
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor debe ser un color válido", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC debe contener una dirección MAC válida", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr debe ser una dirección IP resoluble", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4 debe ser una dirección IPv4 resoluble", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6 debe ser una dirección IPv6 resoluble", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr debe ser una dirección UDP válida", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4 debe ser una dirección IPv4 UDP válida", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6 debe ser una dirección IPv6 UDP válida", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr debe ser una dirección TCP válida", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4 debe ser una dirección IPv4 TCP válida", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6 debe ser una dirección IPv6 TCP válida", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR debe contener una anotación válida del CIDR", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4 debe contener una notación CIDR válida para una dirección IPv4", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6 debe contener una notación CIDR válida para una dirección IPv6", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN debe ser un número válido de SSN", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP debe ser una dirección IP válida", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4 debe ser una dirección IPv4 válida", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6 debe ser una dirección IPv6 válida", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI debe contener un URI de datos válido", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude debe contener coordenadas de latitud válidas", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude debe contener unas coordenadas de longitud válidas", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte debe contener caracteres multibyte", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII debe contener sólo caracteres ascii", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII debe contener sólo caracteres ASCII imprimibles", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID debe ser un UUID válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3 debe ser una versión válida 3 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4 debe ser una versión válida 4 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5 debe ser una versión válida 5 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID debe ser un ULID válido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN debe ser un número ISBN válido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10 debe ser un número ISBN-10 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13 debe ser un número ISBN-13 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes no puede contener el texto 'text'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll no puede contener ninguno de los siguientes caracteres '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune no puede contener lo siguiente '☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny debe contener al menos uno de los siguientes caracteres '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains debe contener el texto 'purpose'", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64 debe ser una cadena de Base64 válida", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email debe ser una dirección de correo electrónico válida", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL debe ser un URL válido", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI debe ser una URI válida", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString debe ser un color RGB válido", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString debe ser un color RGBA válido", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString debe ser un color HSL válido", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString debe ser un color HSL válido", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString debe ser un hexadecimal válido", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString debe ser un color HEX válido", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString debe ser un número válido", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString debe ser un valor numérico válido", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString sólo puede contener caracteres alfanuméricos", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString sólo puede contener caracteres alfabéticos", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString debe ser menor que MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString debe ser menor o igual a MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString debe ser mayor que MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString debe ser mayor o igual a MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString no puede ser igual a EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString debe ser menor que Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString debe ser menor o igual a Inner.LteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString debe ser mayor que Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString debe ser mayor o igual a Inner.GteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString no puede ser igual a Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString debe ser igual a Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString debe ser igual a MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString debe tener al menos 3 caracteres de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber debe ser 5,56 o mayor", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple debe contener al menos 2 elementos", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime debe ser después o durante la fecha y hora actuales", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString debe ser mayor que 3 caracteres en longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber debe ser mayor que 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple debe contener más de 2 elementos", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime debe ser después de la fecha y hora actual", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString debe tener un máximo de 3 caracteres de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber debe ser 5,56 o menos", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple debe contener como máximo 2 elementos", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime debe ser antes o durante la fecha y hora actual", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString debe tener menos de 3 caracteres de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber debe ser menos de 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple debe contener menos de 2 elementos", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime debe ser antes de la fecha y hora actual", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString no debería ser igual a ", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber no debería ser igual a 0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple no debería ser igual a 0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString no es igual a 3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber no es igual a 2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple no es igual a 7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString debe tener un máximo de 3 caracteres de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber debe ser 1.113,00 o menos", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple debe contener como máximo 7 elementos", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString debe tener al menos 1 carácter de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber debe ser 1.113,00 o más", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple debe contener al menos 7 elementos", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString debe tener 1 carácter de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber debe ser igual a 1.113,00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple debe contener 7 elementos", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString es un campo requerido", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber es un campo requerido", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple es un campo requerido", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen debe tener al menos 10 caracteres de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen debe tener un máximo de 1 carácter de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen debe tener 2 caracteres de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt debe tener menos de 1 carácter de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte debe tener un máximo de 1 carácter de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt debe ser mayor que 10 caracteres en longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte debe tener al menos 10 caracteres de longitud", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString debe ser uno de [red green]", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt debe ser uno de [5 63]", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueSlice", |
||||
expected: "UniqueSlice debe contener valores únicos", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueArray", |
||||
expected: "UniqueArray debe contener valores únicos", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueMap", |
||||
expected: "UniqueMap debe contener valores únicos", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,639 @@ |
||||
package id |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
indonesia "github.com/go-playground/locales/id" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
|
||||
idn := indonesia.New() |
||||
uni := ut.New(idn, idn) |
||||
trans, _ := uni.GetTranslator("id") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=tujuan"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=merah hijau"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor harus berupa warna yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC harus berisi alamat MAC yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr harus berupa alamat IP yang dapat dipecahkan", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4 harus berupa alamat IPv4 yang dapat diatasi", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6 harus berupa alamat IPv6 yang dapat diatasi", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr harus berupa alamat UDP yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4 harus berupa alamat IPv4 UDP yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6 harus berupa alamat IPv6 UDP yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr harus berupa alamat TCP yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4 harus berupa alamat TCP IPv4 yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6 harus berupa alamat TCP IPv6 yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR harus berisi notasi CIDR yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4 harus berisi notasi CIDR yang valid untuk alamat IPv4", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6 harus berisi notasi CIDR yang valid untuk alamat IPv6", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN harus berupa nomor SSN yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP harus berupa alamat IP yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4 harus berupa alamat IPv4 yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6 harus berupa alamat IPv6 yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI harus berisi URI Data yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude harus berisi koordinat lintang yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude harus berisi koordinat bujur yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte harus berisi karakter multibyte", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII hanya boleh berisi karakter ascii", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII hanya boleh berisi karakter ascii yang dapat dicetak", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID harus berupa UUID yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3 harus berupa UUID versi 3 yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4 harus berupa UUID versi 4 yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5 harus berupa UUID versi 5 yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID harus berupa ULID yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN harus berupa nomor ISBN yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10 harus berupa nomor ISBN-10 yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13 harus berupa nomor ISBN-13 yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes tidak boleh berisi teks 'text'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll tidak boleh berisi salah satu karakter berikut '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune tidak boleh berisi '☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny harus berisi setidaknya salah satu karakter berikut '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains harus berisi teks 'tujuan'", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64 harus berupa string Base64 yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email harus berupa alamat email yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL harus berupa URL yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI harus berupa URI yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString harus berupa warna RGB yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString harus berupa warna RGBA yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString harus berupa warna HSL yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString harus berupa warna HSLA yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString harus berupa heksadesimal yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString harus berupa warna HEX yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString harus berupa angka yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString harus berupa nilai numerik yang valid", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString hanya dapat berisi karakter alfanumerik", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString hanya dapat berisi karakter abjad", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString harus kurang dari MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString harus kurang dari atau sama dengan MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString harus lebih besar dari MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString harus lebih besar dari atau sama dengan MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString tidak sama dengan EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString harus kurang dari Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString harus kurang dari atau sama dengan Inner.LteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString harus lebih besar dari Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString harus lebih besar dari atau sama dengan Inner.GteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString tidak sama dengan Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString harus sama dengan Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString harus sama dengan MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "panjang minimal GteString adalah 3 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber harus 5,56 atau lebih besar", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple harus berisi setidaknya 2 item", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime harus lebih besar dari atau sama dengan tanggal & waktu saat ini", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "panjang GtString harus lebih dari 3 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber harus lebih besar dari 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple harus berisi lebih dari 2 item", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime harus lebih besar dari tanggal & waktu saat ini", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "panjang maksimal LteString adalah 3 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber harus 5,56 atau kurang", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple harus berisi maksimal 2 item", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime harus kurang dari atau sama dengan tanggal & waktu saat ini", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "panjang LtString harus kurang dari 3 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber harus kurang dari 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple harus berisi kurang dari 2 item", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime harus kurang dari tanggal & waktu saat ini", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString tidak sama dengan ", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber tidak sama dengan 0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple tidak sama dengan 0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString tidak sama dengan 3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber tidak sama dengan 2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple tidak sama dengan 7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "panjang maksimal MaxString adalah 3 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber harus 1.113,00 atau kurang", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple harus berisi maksimal 7 item", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "panjang minimal MinString adalah 1 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber harus 1.113,00 atau lebih besar", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "panjang minimal MinMultiple adalah 7 item", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "panjang LenString harus 1 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber harus sama dengan 1.113,00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple harus berisi 7 item", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString wajib diisi", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber wajib diisi", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple wajib diisi", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "panjang minimal StrPtrMinLen adalah 10 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "panjang maksimal StrPtrMaxLen adalah 1 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "panjang StrPtrLen harus 2 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "panjang StrPtrLt harus kurang dari 1 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "panjang maksimal StrPtrLte adalah 1 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "panjang StrPtrGt harus lebih dari 10 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "panjang minimal StrPtrGte adalah 10 karakter", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString harus berupa salah satu dari [merah hijau]", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt harus berupa salah satu dari [5 63]", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,725 @@ |
||||
package it |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
italian "github.com/go-playground/locales/it" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
ita := italian.New() |
||||
uni := ut.New(ita, ita) |
||||
trans, _ := uni.GetTranslator("it") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
UniqueSlice []string `validate:"unique"` |
||||
UniqueArray [3]string `validate:"unique"` |
||||
UniqueMap map[string]string `validate:"unique"` |
||||
BooleanString string `validate:"boolean"` |
||||
JSONString string `validate:"json"` |
||||
JWTString string `validate:"jwt"` |
||||
LowercaseString string `validate:"lowercase"` |
||||
UppercaseString string `validate:"uppercase"` |
||||
StartsWithString string `validate:"startswith=foo"` |
||||
StartsNotWithString string `validate:"startsnotwith=foo"` |
||||
EndsWithString string `validate:"endswith=foo"` |
||||
EndsNotWithString string `validate:"endsnotwith=foo"` |
||||
Datetime string `validate:"datetime=2006-01-02"` |
||||
PostCode string `validate:"postcode_iso3166_alpha2=SG"` |
||||
PostCodeCountry string |
||||
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
test.LowercaseString = "ABCDEFG" |
||||
test.UppercaseString = "abcdefg" |
||||
|
||||
test.StartsWithString = "hello" |
||||
test.StartsNotWithString = "foo-hello" |
||||
test.EndsWithString = "hello" |
||||
test.EndsNotWithString = "hello-foo" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
test.UniqueSlice = []string{"1234", "1234"} |
||||
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} |
||||
test.Datetime = "2008-Feb-01" |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor deve essere un colore valido", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC deve contenere un indirizzo MAC valido", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr deve essere un indirizzo IP risolvibile", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4 deve essere un indirizzo IPv4 risolvibile", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6 deve essere un indirizzo IPv6 risolvibile", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr deve essere un indirizzo UDP valido", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4 deve essere un indirizzo IPv4 UDP valido", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6 deve essere un indirizzo IPv6 UDP valido", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr deve essere un indirizzo TCP valido", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4 deve essere un indirizzo IPv4 TCP valido", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6 deve essere un indirizzo IPv6 TCP valido", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR deve contenere una notazione CIDR valida", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4 deve contenere una notazione CIDR per un indirizzo IPv4 valida", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6 deve contenere una notazione CIDR per un indirizzo IPv6 valida", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN deve essere un numero SSN valido", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP deve essere un indirizzo IP valido", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4 deve essere un indirizzo IPv4 valido", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6 deve essere un indirizzo IPv6 valido", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI deve contenere un Data URI valido", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude deve contenere una latitudine valida", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude deve contenere una longitudine valida", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte deve contenere caratteri multibyte", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII deve contenere solo caratteri ascii", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII deve contenere solo caratteri ascii stampabili", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID deve essere un UUID valido", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3 deve essere un UUID versione 3 valido", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4 deve essere un UUID versione 4 valido", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5 deve essere un UUID versione 5 valido", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID deve essere un ULID valido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN deve essere un numero ISBN valido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10 deve essere un numero ISBN-10 valido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13 deve essere un numero ISBN-13 valido", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes non deve contenere il testo 'text'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll non deve contenere alcuno dei seguenti caratteri '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune non deve contenere '☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny deve contenere almeno uno dei seguenti caratteri '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains deve contenere il testo 'purpose'", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64 deve essere una stringa Base64 valida", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email deve essere un indirizzo email valido", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL deve essere un URL valido", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI deve essere un URI valido", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString deve essere un colore RGB valido", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString deve essere un colore RGBA valido", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString deve essere un colore HSL valido", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString deve essere un colore HSLA valido", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString deve essere un esadecimale valido", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString deve essere un colore HEX valido", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString deve essere un numero valido", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString deve essere un valore numerico valido", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString può contenere solo caratteri alfanumerici", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString può contenere solo caratteri alfabetici", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString deve essere minore di MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString deve essere minore o uguale a MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString deve essere maggiore di MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString deve essere maggiore o uguale a MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString deve essere diverso da EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString deve essere minore di Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString deve essere minore o uguale a Inner.LteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString deve essere maggiore di Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString deve essere maggiore o uguale a Inner.GteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString deve essere diverso da Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString deve essere uguale a Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString deve essere uguale a MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString deve essere lungo almeno 3 caratteri", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber deve essere maggiore o uguale a 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple deve contenere almeno 2 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime deve essere uguale o successivo alla Data/Ora corrente", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString deve essere lungo più di 3 caratteri", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber deve essere maggiore di 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple deve contenere più di 2 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime deve essere successivo alla Data/Ora corrente", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString deve essere lungo al massimo 3 caratteri", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber deve essere minore o uguale a 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple deve contenere al massimo 2 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime deve essere uguale o precedente alla Data/Ora corrente", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString deve essere lungo meno di 3 caratteri", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber deve essere minore di 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple deve contenere meno di 2 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime deve essere precedente alla Data/Ora corrente", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString deve essere diverso da ", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber deve essere diverso da 0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple deve essere diverso da 0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString non è uguale a 3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber non è uguale a 2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple non è uguale a 7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString deve essere lungo al massimo 3 caratteri", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber deve essere minore o uguale a 1.113,00", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple deve contenere al massimo 7 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString deve essere lungo almeno 1 carattere", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber deve essere maggiore o uguale a 1.113,00", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple deve contenere almeno 7 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString deve essere lungo 1 carattere", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber deve essere uguale a 1.113,00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple deve contenere 7 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString è un campo obbligatorio", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber è un campo obbligatorio", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple è un campo obbligatorio", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen deve essere lungo almeno 10 caratteri", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen deve essere lungo al massimo 1 carattere", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen deve essere lungo 2 caratteri", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt deve essere lungo meno di 1 carattere", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte deve essere lungo al massimo 1 carattere", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt deve essere lungo più di 10 caratteri", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte deve essere lungo almeno 10 caratteri", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString deve essere uno di [red green]", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt deve essere uno di [5 63]", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueSlice", |
||||
expected: "UniqueSlice deve contenere valori unici", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueArray", |
||||
expected: "UniqueArray deve contenere valori unici", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueMap", |
||||
expected: "UniqueMap deve contenere valori unici", |
||||
}, |
||||
{ |
||||
ns: "Test.BooleanString", |
||||
expected: "BooleanString deve rappresentare un valore booleano", |
||||
}, |
||||
{ |
||||
ns: "Test.JSONString", |
||||
expected: "JSONString deve essere una stringa json valida", |
||||
}, |
||||
{ |
||||
ns: "Test.JWTString", |
||||
expected: "JWTString deve essere una stringa jwt valida", |
||||
}, |
||||
{ |
||||
ns: "Test.LowercaseString", |
||||
expected: "LowercaseString deve essere una stringa minuscola", |
||||
}, |
||||
{ |
||||
ns: "Test.UppercaseString", |
||||
expected: "UppercaseString deve essere una stringa maiuscola", |
||||
}, |
||||
{ |
||||
ns: "Test.StartsWithString", |
||||
expected: "StartsWithString deve iniziare con foo", |
||||
}, |
||||
{ |
||||
ns: "Test.StartsNotWithString", |
||||
expected: "StartsNotWithString non deve iniziare con foo", |
||||
}, |
||||
{ |
||||
ns: "Test.EndsWithString", |
||||
expected: "EndsWithString deve terminare con foo", |
||||
}, |
||||
{ |
||||
ns: "Test.EndsNotWithString", |
||||
expected: "EndsNotWithString non deve terminare con foo", |
||||
}, |
||||
{ |
||||
ns: "Test.Datetime", |
||||
expected: "Datetime non corrisponde al formato 2006-01-02", |
||||
}, |
||||
{ |
||||
ns: "Test.PostCode", |
||||
expected: "PostCode non corrisponde al formato del codice postale dello stato SG", |
||||
}, |
||||
{ |
||||
ns: "Test.PostCodeByField", |
||||
expected: "PostCodeByField non corrisponde al formato del codice postale dello stato nel campo PostCodeCountry", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,710 @@ |
||||
package ja |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
ja_locale "github.com/go-playground/locales/ja" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
japanese := ja_locale.New() |
||||
uni := ut.New(japanese, japanese) |
||||
trans, _ := uni.GetTranslator("ja") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
RequiredIf string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
UniqueSlice []string `validate:"unique"` |
||||
UniqueArray [3]string `validate:"unique"` |
||||
UniqueMap map[string]string `validate:"unique"` |
||||
JSONString string `validate:"json"` |
||||
JWTString string `validate:"jwt"` |
||||
LowercaseString string `validate:"lowercase"` |
||||
UppercaseString string `validate:"uppercase"` |
||||
Datetime string `validate:"datetime=2006-01-02"` |
||||
PostCode string `validate:"postcode_iso3166_alpha2=SG"` |
||||
PostCodeCountry string |
||||
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` |
||||
BooleanString string `validate:"boolean"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
test.LowercaseString = "ABCDEFG" |
||||
test.UppercaseString = "abcdefg" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
test.UniqueSlice = []string{"1234", "1234"} |
||||
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} |
||||
test.Datetime = "2008-Feb-01" |
||||
test.BooleanString = "A" |
||||
|
||||
test.Inner.RequiredIf = "abcd" |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColorは正しい色でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MACは正しいMACアドレスを含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddrは解決可能なIPアドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4は解決可能なIPv4アドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6は解決可能なIPv6アドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddrは正しいUDPアドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4は正しいIPv4のUDPアドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6は正しいIPv6のUDPアドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddrは正しいTCPアドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4は正しいIPv4のTCPアドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6は正しいIPv6のTCPアドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDRは正しいCIDR表記を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4はIPv4アドレスの正しいCIDR表記を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6はIPv6アドレスの正しいCIDR表記を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSNは正しい社会保障番号でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IPは正しいIPアドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4は正しいIPv4アドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6は正しいIPv6アドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURIは正しいデータURIを含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitudeは正しい緯度の座標を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitudeは正しい経度の座標を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByteはマルチバイト文字を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCIIはASCII文字のみを含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCIIは印刷可能なASCII文字のみを含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUIDは正しいUUIDでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3はバージョンが3の正しいUUIDでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4はバージョンが4の正しいUUIDでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5はバージョンが5の正しいUUIDでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULIDは正しいULIDでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBNは正しいISBN番号でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10は正しいISBN-10番号でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13は正しいISBN-13番号でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludesには'text'というテキストを含むことはできません", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAllには'!@#$'のどれも含めることはできません", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRuneには'☻'を含めることはできません", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAnyは'!@#$'の少なくとも1つを含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Containsは'purpose'を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64は正しいBase64文字列でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Emailは正しいメールアドレスでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URLは正しいURLでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URIは正しいURIでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorStringは正しいRGBカラーコードでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorStringは正しいRGBAカラーコードでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorStringは正しいHSLカラーコードでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorStringは正しいHSLAカラーコードでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalStringは正しい16進表記でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorStringは正しいHEXカラーコードでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberStringは正しい数でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericStringは正しい数字でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumStringはアルファベットと数字のみを含むことができます", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaStringはアルファベットのみを含むことができます", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldStringはMaxStringよりも小さくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldStringはMaxString以下でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldStringはMaxStringよりも大きくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldStringはMaxString以上でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldStringはEqFieldStringとは異ならなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldStringはInner.LtCSFieldStringよりも小さくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldStringはInner.LteCSFieldString以下でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldStringはInner.GtCSFieldStringよりも大きくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldStringはInner.GteCSFieldString以上でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldStringはInner.NeCSFieldStringとは異ならなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldStringはInner.EqCSFieldStringと等しくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldStringはMaxStringと等しくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteStringの長さは少なくとも3文字以上はなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumberは5.56以上でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultipleは少なくとも2つの項目を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTimeは現時刻以降でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtStringの長さは3文字よりも多くなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumberは5.56よりも大きくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultipleは2つの項目よりも多い項目を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTimeは現時刻よりも後でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteStringの長さは最大でも3文字でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumberは5.56以下でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultipleは最大でも2つの項目を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTimeは現時刻以前でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtStringの長さは3文字よりも少なくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumberは5.56よりも小さくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultipleは2つの項目よりも少ない項目を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTimeは現時刻よりも前でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeStringはと異ならなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumberは0.00と異ならなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultipleの項目の数は0個と異ならなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqStringは3と等しくありません", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumberは2.33と等しくありません", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultipleは7と等しくありません", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxStringの長さは最大でも3文字でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumberは1,113.00以下でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultipleは最大でも7つの項目を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinStringの長さは少なくとも1文字はなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumberは1,113.00以上でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultipleは少なくとも7つの項目を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenStringの長さは1文字でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumberは1,113.00と等しくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultipleは7つの項目を含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredStringは必須フィールドです", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredIf", |
||||
expected: "RequiredIfは必須フィールドです", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumberは必須フィールドです", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultipleは必須フィールドです", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLenの長さは少なくとも10文字はなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLenの長さは最大でも1文字でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLenの長さは2文字でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLtの長さは1文字よりも少なくなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLteの長さは最大でも1文字でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGtの長さは10文字よりも多くなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGteの長さは少なくとも10文字以上はなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfStringは[red green]のうちのいずれかでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfIntは[5 63]のうちのいずれかでなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueSlice", |
||||
expected: "UniqueSliceは一意な値のみを含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueArray", |
||||
expected: "UniqueArrayは一意な値のみを含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueMap", |
||||
expected: "UniqueMapは一意な値のみを含まなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.JSONString", |
||||
expected: "JSONStringは正しいJSON文字列でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.JWTString", |
||||
expected: "JWTStringは正しいJWT文字列でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.LowercaseString", |
||||
expected: "LowercaseStringは小文字でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.UppercaseString", |
||||
expected: "UppercaseStringは大文字でなければなりません", |
||||
}, |
||||
{ |
||||
ns: "Test.Datetime", |
||||
expected: "Datetimeは2006-01-02の書式と一致しません", |
||||
}, |
||||
{ |
||||
ns: "Test.PostCode", |
||||
expected: "PostCodeは国名コードSGの郵便番号形式と一致しません", |
||||
}, |
||||
{ |
||||
ns: "Test.PostCodeByField", |
||||
expected: "PostCodeByFieldはPostCodeCountryフィールドで指定された国名コードの郵便番号形式と一致しません", |
||||
}, |
||||
{ |
||||
ns: "Test.BooleanString", |
||||
expected: "BooleanStringは正しいブール値でなければなりません", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,709 @@ |
||||
package lv |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
english "github.com/go-playground/locales/en" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
eng := english.New() |
||||
uni := ut.New(eng, eng) |
||||
trans, _ := uni.GetTranslator("en") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
RequiredIf string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
UniqueSlice []string `validate:"unique"` |
||||
UniqueArray [3]string `validate:"unique"` |
||||
UniqueMap map[string]string `validate:"unique"` |
||||
JSONString string `validate:"json"` |
||||
JWTString string `validate:"jwt"` |
||||
LowercaseString string `validate:"lowercase"` |
||||
UppercaseString string `validate:"uppercase"` |
||||
Datetime string `validate:"datetime=2006-01-02"` |
||||
PostCode string `validate:"postcode_iso3166_alpha2=SG"` |
||||
PostCodeCountry string |
||||
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` |
||||
BooleanString string `validate:"boolean"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
test.LowercaseString = "ABCDEFG" |
||||
test.UppercaseString = "abcdefg" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
test.UniqueSlice = []string{"1234", "1234"} |
||||
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} |
||||
test.Datetime = "2008-Feb-01" |
||||
test.BooleanString = "A" |
||||
|
||||
test.Inner.RequiredIf = "abcd" |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor jābūt derīgai krāsai", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC jābūt derīgai MAC adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr jābūt atrisināmai IP adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4 jābūt atrisināmai IPv4 adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6 jābūt atrisināmai IPv6 adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr jābūt derīgai UDP adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4 jābūt derīgai IPv4 UDP adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6 jābūt derīgai IPv6 UDP adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr jābūt derīgai TCP adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4 jābūt derīgai IPv4 TCP adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6 jābūt derīgai IPv6 TCP adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR jāsatur derīgu CIDR notāciju", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4 jāsatur derīgu CIDR notāciju IPv4 adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6 jāsatur derīgu CIDR notāciju IPv6 adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN jābūt derīgam SSN numuram", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP jābūt derīgai IP adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4 jābūt derīgai IPv4 adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6 jābūt derīgai IPv6 adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI jāsatur derīgs Data URI", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude jāsatur derīgus platuma grādus", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude jāsatur derīgus garuma grādus", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte jāsatur multibyte rakstu zīmes", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII jāsatur tikai ascii rakstu zīmes", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII jāsatur tikai drukājamas ascii rakstu zīmes", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID jābūt derīgam UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3 jābūt derīgam 3. versijas UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4 jābūt derīgam 4. versijas UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5 jābūt derīgam 5. versijas UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID jābūt derīgam ULID", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN jābūt derīgam ISBN numuram", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10 jābūt derīgam ISBN-10 numuram", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13 jābūt derīgam ISBN-13 numuram", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes nedrīkst saturēt tekstu 'text'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll nedrīkst saturēt nevienu no sekojošām rakstu zīmēm '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune nedrīkst saturēt sekojošo '☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny jāsatur minimums 1 no rakstu zīmēm '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains jāsatur teksts 'purpose'", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64 jābūt derīgai Base64 virknei", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email jābūt derīgai e-pasta adresei", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL jābūt derīgam URL", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI jābūt derīgam URI", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString jābūt derīgai RGB krāsai", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString jābūt derīgai RGBA krāsai", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString jābūt derīgai HSL krāsai", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString jābūt derīgai HSLA krāsai", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString jābūt heksadecimālam skaitlim", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString jābūt derīgai HEX krāsai", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString jāsatur derīgs skaitlis", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString jāsatur tikai cipari", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString jāsatur tikai simboli no alfabēta vai cipari (Alphanumeric)", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString jāsatur tikai simboli no alfabēta", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString jābūt mazākam par MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString jābūt mazākam par MaxString vai vienādam", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString jābūt lielākam par MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString jābūt lielākam par MaxString vai vienādam", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString nedrīkst būt vienāds ar EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString jābūt mazākam par Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString jābūt mazākam par Inner.LteCSFieldString vai vienādam", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString jābūt lielākam par Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString jābūt lielākam par Inner.GteCSFieldString vai vienādam", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString nedrīkst būt vienāds ar Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString jābūt vienādam ar Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString jābūt vienādam ar MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString garumam jābūt minimums 3 rakstu zīmes", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber jābūt 5.56 vai lielākam", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple jāsatur minimums 2 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime jābūt lielākam par šī brīža Datumu un laiku vai vienādam", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString ir jābūt garākam par 3 rakstu zīmēm", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber jābūt lielākam par 5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple jāsatur vairāk par 2 elementiem", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime jābūt lielākam par šī brīža Datumu un laiku", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString garumam jābūt maksimums 3 rakstu zīmes", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber jābūt 5.56 vai mazākam", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple jāsatur maksimums 2 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime jābūt mazākam par šī brīža Datumu un laiku vai vienādam", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString garumam jābūt mazākam par 3 rakstu zīmēm", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber jābūt mazākam par 5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple jāsatur mazāk par 2 elementiem", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime jābūt mazākam par šī brīža Datumu un laiku", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString nedrīkst būt vienāds ar ", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber nedrīkst būt vienāds ar 0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple nedrīkst būt vienāds ar 0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString nav vienāds ar 3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber nav vienāds ar 2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple nav vienāds ar 7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString vērtība pārsniedz maksimālo garumu 3 rakstu zīmes", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber vērtībai jābūt 1,113.00 vai mazākai", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple jāsatur maksimums 7 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString garumam jābūt minimums 1 rakstu zīme", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber vērtībai jābūt 1,113.00 vai lielākai", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple jāsatur minimums 7 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString garumam jābūt 1 rakstu zīme", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber vērtībai jābūt 1,113.00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple vērtībai jāsatur 7 elementi", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString ir obligāts lauks", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredIf", |
||||
expected: "RequiredIf ir obligāts lauks", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber ir obligāts lauks", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple ir obligāts lauks", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen garumam jābūt minimums 10 rakstu zīmes", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen vērtība pārsniedz maksimālo garumu 1 rakstu zīme", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen garumam jābūt 2 rakstu zīmes", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt garumam jābūt mazākam par 1 rakstu zīmi", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte garumam jābūt maksimums 1 rakstu zīme", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt ir jābūt garākam par 10 rakstu zīmēm", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte garumam jābūt minimums 10 rakstu zīmes", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString jābūt vienam no [red green]", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt jābūt vienam no [5 63]", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueSlice", |
||||
expected: "UniqueSlice jāsatur unikālas vērtības", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueArray", |
||||
expected: "UniqueArray jāsatur unikālas vērtības", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueMap", |
||||
expected: "UniqueMap jāsatur unikālas vērtības", |
||||
}, |
||||
{ |
||||
ns: "Test.JSONString", |
||||
expected: "JSONString jābūt derīgai json virknei", |
||||
}, |
||||
{ |
||||
ns: "Test.JWTString", |
||||
expected: "JWTString jābūt derīgai jwt virknei", |
||||
}, |
||||
{ |
||||
ns: "Test.LowercaseString", |
||||
expected: "LowercaseString jābūt mazo burtu virknei", |
||||
}, |
||||
{ |
||||
ns: "Test.UppercaseString", |
||||
expected: "UppercaseString jābūt lielo burtu virknei", |
||||
}, |
||||
{ |
||||
ns: "Test.Datetime", |
||||
expected: "Datetime neatbilst formātam 2006-01-02", |
||||
}, |
||||
{ |
||||
ns: "Test.PostCode", |
||||
expected: "PostCode neatbilst pasta indeksa formātam valstī SG", |
||||
}, |
||||
{ |
||||
ns: "Test.PostCodeByField", |
||||
expected: "PostCodeByField neatbilst pasta indeksa formātam valstī, kura norādīta laukā PostCodeCountry", |
||||
}, |
||||
{ |
||||
ns: "Test.BooleanString", |
||||
expected: "BooleanString jābūt derīgai boolean vērtībai", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,639 @@ |
||||
package nl |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
english "github.com/go-playground/locales/en" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
|
||||
eng := english.New() |
||||
uni := ut.New(eng, eng) |
||||
trans, _ := uni.GetTranslator("en") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor moet een geldige kleur zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC moet een geldig MAC adres bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr moet een oplosbaar IP adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4 moet een oplosbaar IPv4 adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6 moet een oplosbaar IPv6 adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr moet een geldig UDP adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4 moet een geldig IPv4 UDP adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6 moet een geldig IPv6 UDP adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr moet een geldig TCP adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4 moet een geldig IPv4 TCP adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6 moet een geldig IPv6 TCP adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR moet een geldige CIDR notatie bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4 moet een geldige CIDR notatie voor een IPv4 adres bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6 moet een geldige CIDR notatie voor een IPv6 adres bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN moet een geldig SSN nummer zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP moet een geldig IP adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4 moet een geldig IPv4 adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6 moet een geldig IPv6 adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI moet een geldige Data URI bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude moet geldige breedtegraadcoördinaten bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude moet geldige lengtegraadcoördinaten bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte moet multibyte karakters bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII mag alleen ascii karakters bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII mag alleen afdrukbare ascii karakters bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID moet een geldige UUID zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3 moet een geldige versie 3 UUID zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4 moet een geldige versie 4 UUID zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5 moet een geldige versie 5 UUID zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID moet een geldige ULID zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN moet een geldig ISBN nummer zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10 moet een geldig ISBN-10 nummer zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13 moet een geldig ISBN-13 nummer zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes mag niet de tekst 'text' bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll mag niet een van de volgende karakters bevatten '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune mag niet het volgende bevatten '☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny moet tenminste een van de volgende karakters bevatten '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains moet de tekst 'purpose' bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64 moet een geldige Base64 string zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email moet een geldig email adres zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL moet een geldige URL zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI moet een geldige URI zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString moet een geldige RGB kleur zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString moet een geldige RGBA kleur zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString moet een geldige HSL kleur zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString moet een geldige HSLA kleur zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString moet een geldig hexadecimaal getal zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString moet een geldige HEX kleur zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString moet een geldig getal zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString moet een geldige numerieke waarde zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString mag alleen alfanumerieke karakters bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString mag alleen alfabetische karakters bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString moet kleiner zijn dan MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString moet kleiner dan of gelijk aan MaxString zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString moet groter zijn dan MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString moet groter dan of gelijk aan MaxString zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString mag niet gelijk zijn aan EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString moet kleiner zijn dan Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString moet kleiner dan of gelijk aan Inner.LteCSFieldString zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString moet groter zijn dan Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString moet groter dan of gelijk aan Inner.GteCSFieldString zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString mag niet gelijk zijn aan Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString moet gelijk zijn aan Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString moet gelijk zijn aan MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString moet tenminste 3 karakters lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber moet 5.56 of groter zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple moet tenminste 2 items bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime moet groter dan of gelijk zijn aan de huidige datum & tijd", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString moet langer dan 3 karakters zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber moet groter zijn dan 5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple moet meer dan 2 items bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime moet groter zijn dan de huidige datum & tijd", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString mag maximaal 3 karakters lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber moet 5.56 of minder zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple mag maximaal 2 items bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime moet kleiner dan of gelijk aan de huidige datum & tijd zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString moet minder dan 3 karakters lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber moet kleiner zijn dan 5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple moet minder dan 2 items bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime moet kleiner zijn dan de huidige datum & tijd", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString mag niet gelijk zijn aan ", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber mag niet gelijk zijn aan 0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple mag niet gelijk zijn aan 0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString is niet gelijk aan 3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber is niet gelijk aan 2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple is niet gelijk aan 7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString mag maximaal 3 karakters lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber moet 1,113.00 of kleiner zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple mag maximaal 7 items bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString moet tenminste 1 karakter lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber moet 1,113.00 of groter zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple moet tenminste 7 items bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString moet 1 karakter lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber moet gelijk zijn aan 1,113.00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple moet 7 items bevatten", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString is een verplicht veld", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber is een verplicht veld", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple is een verplicht veld", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen moet tenminste 10 karakters lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen mag maximaal 1 karakter lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen moet 2 karakters lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt moet minder dan 1 karakter lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte mag maximaal 1 karakter lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt moet langer dan 10 karakters zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte moet tenminste 10 karakters lang zijn", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString moet een van de volgende zijn [red green]", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt moet een van de volgende zijn [5 63]", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,682 @@ |
||||
package pt |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
"github.com/go-playground/locales/pt" |
||||
ut "github.com/go-playground/universal-translator" |
||||
|
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
|
||||
pt := pt.New() |
||||
uni := ut.New(pt, pt) |
||||
trans, _ := uni.GetTranslator("pt") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
UniqueSlice []string `validate:"unique"` |
||||
UniqueArray [3]string `validate:"unique"` |
||||
UniqueMap map[string]string `validate:"unique"` |
||||
JSONString string `validate:"json"` |
||||
LowercaseString string `validate:"lowercase"` |
||||
UppercaseString string `validate:"uppercase"` |
||||
Datetime string `validate:"datetime=2006-01-02"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
test.LowercaseString = "ABCDEFG" |
||||
test.UppercaseString = "abcdefg" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
test.UniqueSlice = []string{"1234", "1234"} |
||||
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} |
||||
test.Datetime = "2008-Feb-01" |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor deve ser uma cor válida", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC deve conter um endereço MAC válido", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr deve ser um endereço IP resolvível", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4 deve ser um endereço IPv4 resolvível", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6 deve ser um endereço IPv6 resolvível", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr deve ser um endereço UDP válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4 deve ser um endereço UDP IPv4 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6 deve ser um endereço UDP IPv6 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr deve ser um endereço TCP válido", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4 deve ser um endereço TCP IPv4 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6 deve ser um endereço TCP IPv6 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR não respeita a notação CIDR", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4 não respeita a notação CIDR para um endereço IPv4", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6 não respeita a notação CIDR para um endereço IPv6", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN deve ser um número SSN válido", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP deve ser um endereço IP válido", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4 deve ser um endereço IPv4 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6 deve ser um endereço IPv6 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI deve conter um Data URI válido", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude deve conter uma coordenada de latitude válida", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude deve conter uma coordenada de longitude válida", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte deve conter caracteres multibyte", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII deve conter apenas caracteres ascii", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII deve conter apenas caracteres ascii imprimíveis", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID deve ser um UUID válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3 deve ser um UUID versão 3 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4 deve ser um UUID versão 4 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5 deve ser um UUID versão 5 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID deve ser um ULID válido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN deve ser um número de ISBN válido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10 deve ser um número ISBN-10 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13 deve ser um número ISBN-13 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes não deve conter o texto 'text'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll não deve conter os seguintes caracteres '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune não pode conter o seguinte '☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny deve conter pelo menos um dos seguintes caracteres '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains deve conter o texto 'purpose'", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64 deve ser uma string Base64 válida", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email deve ser um endereço de e-mail válido", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL deve ser um URL válido", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI deve ser um URI válido", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString deve ser uma cor RGB válida", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString deve ser uma cor RGBA válida", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString deve ser uma cor HSL válida", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString deve ser uma cor HSLA válida", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString deve ser um hexadecimal válido", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString deve ser uma cor HEX válida", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString deve ser um número válido", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString deve ser um valor numérico válido", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString deve conter apenas caracteres alfanuméricos", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString deve conter apenas caracteres alfabéticos", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString deve ser menor que MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString deve ser menor ou igual que MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString deve ser maior que MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString deve ser maior ou igual que MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString não deve ser igual a EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString deve ser menor que Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString deve ser menor ou igual que Inner.LteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString deve ser maior que Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString deve ser maior ou igual que Inner.GteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString não deve ser igual a Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString deve ser igual a Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString deve ser igual a MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString deve ter pelo menos 3 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber deve ser maior ou igual a 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple deve conter pelo menos 2 items", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime deve ser posterior ou igual à data/hora atual", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString deve conter mais de 3 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber deve ser maior que 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple deve conter mais de 2 items", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime deve ser posterior à data/hora atual", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString deve ter no máximo 3 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber deve ser menor ou igual a 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple deve conter no máximo 2 items", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime deve ser anterior ou igual à data/hora atual", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString deve ter menos de 3 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber deve ser menor que 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple deve conter menos de 2 items", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime deve ser anterior à data / hora atual", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString não deve ser igual a ", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber não deve ser igual a 0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple não deve ser igual a 0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString não é igual a 3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber não é igual a 2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple não é igual a 7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString deve ter no máximo 3 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber deve ser 1.113,00 ou menos", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple deve conter no máximo 7 items", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString deve ter pelo menos 1 caractere", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber deve ser 1.113,00 ou superior", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple deve conter pelo menos 7 items", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString deve ter 1 caractere", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber deve ser igual a 1.113,00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple deve conter 7 items", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString é obrigatório", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber é obrigatório", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple é obrigatório", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen deve ter pelo menos 10 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen deve ter no máximo 1 caractere", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen deve ter 2 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt deve ter menos de 1 caractere", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte deve ter no máximo 1 caractere", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt deve conter mais de 10 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte deve ter pelo menos 10 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString deve ser um de [red green]", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt deve ser um de [5 63]", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueSlice", |
||||
expected: "UniqueSlice deve conter valores únicos", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueArray", |
||||
expected: "UniqueArray deve conter valores únicos", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueMap", |
||||
expected: "UniqueMap deve conter valores únicos", |
||||
}, |
||||
{ |
||||
ns: "Test.JSONString", |
||||
expected: "JSONString deve ser uma string json válida", |
||||
}, |
||||
{ |
||||
ns: "Test.LowercaseString", |
||||
expected: "LowercaseString deve estar em minuscúlas", |
||||
}, |
||||
{ |
||||
ns: "Test.UppercaseString", |
||||
expected: "UppercaseString deve estar em maiúsculas", |
||||
}, |
||||
{ |
||||
ns: "Test.Datetime", |
||||
expected: "Datetime não está no formato 2006-01-02", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,651 @@ |
||||
package pt_BR |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
brazilian_portuguese "github.com/go-playground/locales/pt_BR" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
|
||||
ptbr := brazilian_portuguese.New() |
||||
uni := ut.New(ptbr, ptbr) |
||||
trans, _ := uni.GetTranslator("pt_BR") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
BooleanString string `validate:"boolean"` |
||||
CveString string `validate:"cve"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
test.BooleanString = "A" |
||||
test.CveString = "A" |
||||
|
||||
test.Excludes = "este é um texto de teste" |
||||
test.ExcludesAll = "Isso é Ótimo!" |
||||
test.ExcludesRune = "Amo isso ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor deve ser uma cor válida", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC deve conter um endereço MAC válido", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr deve ser um endereço IP resolvível", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4 deve ser um endereço IPv4 resolvível", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6 deve ser um endereço IPv6 resolvível", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr deve ser um endereço UDP válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4 deve ser um endereço IPv4 UDP válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6 deve ser um endereço IPv6 UDP válido", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr deve ser um endereço TCP válido", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4 deve ser um endereço IPv4 TCP válido", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6 deve ser um endereço IPv6 TCP válido", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR deve conter uma notação CIDR válida", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4 deve conter uma notação CIDR válida para um endereço IPv4", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6 deve conter uma notação CIDR válida para um endereço IPv6", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN deve ser um número SSN válido", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP deve ser um endereço de IP válido", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4 deve ser um endereço IPv4 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6 deve ser um endereço IPv6 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI deve conter um URI data válido", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude deve conter uma coordenada de latitude válida", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude deve conter uma coordenada de longitude válida", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte deve conter caracteres multibyte", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII deve conter apenas caracteres ascii", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII deve conter apenas caracteres ascii imprimíveis", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID deve ser um UUID válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3 deve ser um UUID versão 3 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4 deve ser um UUID versão 4 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5 deve ser um UUID versão 5 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID deve ser uma ULID válida", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN deve ser um número ISBN válido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10 deve ser um número ISBN-10 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13 deve ser um número ISBN-13 válido", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes não deve conter o texto 'text'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll não deve conter nenhum dos caracteres '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune não deve conter '☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny deve conter pelo menos um dos caracteres '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains deve conter o texto 'purpose'", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64 deve ser uma string Base64 válida", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email deve ser um endereço de e-mail válido", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL deve ser uma URL válida", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI deve ser uma URI válida", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString deve ser uma cor RGB válida", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString deve ser uma cor RGBA válida", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString deve ser uma cor HSL válida", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString deve ser uma cor HSLA válida", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString deve ser um hexadecimal válido", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString deve ser uma cor HEX válida", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString deve ser um número válido", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString deve ser um valor numérico válido", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString deve conter caracteres alfanuméricos", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString deve conter caracteres alfabéticos", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString deve ser menor que MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString deve ser menor ou igual a MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString deve ser maior do que MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString deve ser maior ou igual a MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString não deve ser igual a EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString deve ser menor que Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString deve ser menor ou igual a Inner.LteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString deve ser maior do que Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString deve ser maior ou igual a Inner.GteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString não deve ser igual a Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString deve ser igual a Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString deve ser igual a MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString deve ter pelo menos 3 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber deve ser 5,56 ou superior", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple deve conter pelo menos 2 itens", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime deve ser maior ou igual à Data e Hora atual", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString deve ter mais de 3 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber deve ser maior do que 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple deve conter mais de 2 itens", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime deve ser maior que a Data e Hora atual", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString deve ter no máximo 3 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber deve ser 5,56 ou menor", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple deve conter no máximo 2 itens", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime deve ser menor ou igual à Data e Hora atual", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString deve ter menos de 3 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber deve ser menor que 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple deve conter menos de 2 itens", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime deve ser inferior à Data e Hora atual", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString não deve ser igual a ", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber não deve ser igual a 0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple não deve ser igual a 0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString não é igual a 3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber não é igual a 2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple não é igual a 7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString deve ter no máximo 3 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber deve ser 1.113,00 ou menor", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple deve conter no máximo 7 itens", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString deve ter pelo menos 1 caractere", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber deve ser 1.113,00 ou superior", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple deve conter pelo menos 7 itens", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString deve ter 1 caractere", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber deve ser igual a 1.113,00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple deve conter 7 itens", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString é um campo obrigatório", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber é um campo obrigatório", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple é um campo obrigatório", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen deve ter pelo menos 10 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen deve ter no máximo 1 caractere", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen deve ter 2 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt deve ter menos de 1 caractere", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte deve ter no máximo 1 caractere", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt deve ter mais de 10 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte deve ter pelo menos 10 caracteres", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString deve ser um de [red green]", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt deve ser um de [5 63]", |
||||
}, |
||||
{ |
||||
ns: "Test.BooleanString", |
||||
expected: "BooleanString deve ser um valor booleano válido", |
||||
}, |
||||
{ |
||||
ns: "Test.CveString", |
||||
expected: "CveString deve ser um identificador cve válido", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,657 @@ |
||||
package tr |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
turkish "github.com/go-playground/locales/tr" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
|
||||
tr := turkish.New() |
||||
uni := ut.New(tr, tr) |
||||
trans, _ := uni.GetTranslator("tr") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
UniqueSlice []string `validate:"unique"` |
||||
UniqueArray [3]string `validate:"unique"` |
||||
UniqueMap map[string]string `validate:"unique"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
test.UniqueSlice = []string{"1234", "1234"} |
||||
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor geçerli bir renk olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC geçerli bir MAC adresi içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr çözülebilir bir IP adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4 çözülebilir bir IPv4 adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6 çözülebilir bir IPv6 adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr geçerli bir UDP adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4 geçerli bir IPv4 UDP adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6 geçerli bir IPv6 UDP adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr geçerli bir TCP adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4 geçerli bir IPv4 TCP adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6 geçerli bir IPv6 TCP adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR geçerli bir CIDR gösterimi içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4 bir IPv4 adresi için geçerli bir CIDR gösterimi içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6 bir IPv6 adresi için geçerli bir CIDR gösterimi içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN geçerli bir SSN numarası olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP geçerli bir IP adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4 geçerli bir IPv4 adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6 geçerli bir IPv6 adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI geçerli bir Veri URI içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude geçerli bir enlem koordinatı içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude geçerli bir boylam koordinatı içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte çok baytlı karakterler içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII yalnızca ascii karakterler içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII yalnızca yazdırılabilir ascii karakterleri içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID geçerli bir UUID olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3 geçerli bir sürüm 3 UUID olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4 geçerli bir sürüm 4 UUID olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5 geçerli bir sürüm 5 UUID olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID geçerli bir ULID olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN geçerli bir ISBN numarası olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10 geçerli bir ISBN-10 numarası olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13 geçerli bir ISBN-13 numarası olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes, 'text' metnini içeremez", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll, '!@#$' karakterlerinden hiçbirini içeremez", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune, '☻' ifadesini içeremez", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny, '!@#$' karakterlerinden en az birini içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains, 'purpose' metnini içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64 geçerli bir Base64 karakter dizesi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email geçerli bir e-posta adresi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL geçerli bir URL olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI geçerli bir URI olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString geçerli bir RGB rengi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString geçerli bir RGBA rengi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString geçerli bir HSL rengi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString geçerli bir HSLA rengi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString geçerli bir onaltılık olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString geçerli bir HEX rengi olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString geçerli bir sayı olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString geçerli bir sayısal değer olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString yalnızca alfanümerik karakterler içerebilir", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString yalnızca alfabetik karakterler içerebilir", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString, MaxString değerinden küçük olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString, MaxString değerinden küçük veya ona eşit olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString, MaxString değerinden büyük olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString, MaxString değerinden büyük veya ona eşit olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString, EqFieldString değerine eşit olmamalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString, Inner.LtCSFieldString değerinden küçük olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString, Inner.LteCSFieldString değerinden küçük veya ona eşit olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString, Inner.GtCSFieldString değerinden büyük olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString, Inner.GteCSFieldString değerinden küçük veya ona eşit olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString, Inner.NeCSFieldString değerine eşit olmamalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString, Inner.EqCSFieldString değerine eşit olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString, MaxString değerine eşit olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString en az 3 karakter uzunluğunda olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber, 5,56 veya daha büyük olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple en az 2 öğe içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime geçerli Tarih ve Saatten büyük veya ona eşit olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString, 3 karakter uzunluğundan fazla olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber, 5,56 değerinden büyük olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple, 2 öğeden daha fazla içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime geçerli Tarih ve Saatten büyük olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString en fazla 3 karakter uzunluğunda olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber, 5,56 veya daha az olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple, maksimum 2 öğe içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime geçerli Tarih ve Saate eşit veya daha küçük olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString, 3 karakter uzunluğundan daha az olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber, 5,56 değerinden küçük olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple, 2 öğeden daha az içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime geçerli Tarih ve Saatten daha az olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString, değerine eşit olmamalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber, 0.00 değerine eşit olmamalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple, 0 değerine eşit olmamalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString, 3 değerine eşit değil", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber, 2.33 değerine eşit değil", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple, 7 değerine eşit değil", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString uzunluğu en fazla 3 karakter olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber, 1.113,00 veya daha az olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple maksimum 7 öğe içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString en az 1 karakter uzunluğunda olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber, 1.113,00 veya daha büyük olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple en az 7 öğe içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString uzunluğu 1 karakter olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber, 1.113,00 değerine eşit olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple, 7 öğe içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString zorunlu bir alandır", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber zorunlu bir alandır", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple zorunlu bir alandır", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen en az 10 karakter uzunluğunda olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen uzunluğu en fazla 1 karakter olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen uzunluğu 2 karakter olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt, 1 karakter uzunluğundan daha az olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte en fazla 1 karakter uzunluğunda olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt, 10 karakter uzunluğundan fazla olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte en az 10 karakter uzunluğunda olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString, [red green]'dan biri olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt, [5 63]'dan biri olmalıdır", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueSlice", |
||||
expected: "UniqueSlice benzersiz değerler içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueArray", |
||||
expected: "UniqueArray benzersiz değerler içermelidir", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueMap", |
||||
expected: "UniqueMap benzersiz değerler içermelidir", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,690 @@ |
||||
package vi |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
vietnamese "github.com/go-playground/locales/vi" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
vie := vietnamese.New() |
||||
uni := ut.New(vie, vie) |
||||
trans, _ := uni.GetTranslator("vi") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
UniqueSlice []string `validate:"unique"` |
||||
UniqueArray [3]string `validate:"unique"` |
||||
UniqueMap map[string]string `validate:"unique"` |
||||
JSONString string `validate:"json"` |
||||
JWTString string `validate:"jwt"` |
||||
LowercaseString string `validate:"lowercase"` |
||||
UppercaseString string `validate:"uppercase"` |
||||
Datetime string `validate:"datetime=2006-01-02"` |
||||
PostCode string `validate:"postcode_iso3166_alpha2=SG"` |
||||
PostCodeCountry string |
||||
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
test.LowercaseString = "ABCDEFG" |
||||
test.UppercaseString = "abcdefg" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
test.UniqueSlice = []string{"1234", "1234"} |
||||
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} |
||||
test.Datetime = "2008-Feb-01" |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor phải là màu sắc hợp lệ", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC chỉ được chứa địa chỉ MAC", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr phải là địa chỉ IP có thể phân giải", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4 phải là địa chỉ IPv4 có thể phân giải", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6 phải là địa chỉ IPv6 có thể phân giải", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr phải là địa chỉ UDP", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4 phải là địa chỉ IPv4 UDP", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6 phải là địa chỉ IPv6 UDP", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr phải là địa chỉ TCP", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4 phải là địa chỉ IPv4 TCP", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6 phải là địa chỉ IPv6 TCP", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR chỉ được chứa CIDR notation", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4 chỉ được chứa CIDR notation của một địa chỉ IPv4", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6 chỉ được chứa CIDR notation của một địa chỉ IPv6", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN phải là SSN number", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP phải là địa chỉ IP", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4 phải là địa chỉ IPv4", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6 phải là địa chỉ IPv6", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI chỉ được chứa Data URI", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude chỉ được chứa latitude (vỹ độ)", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude chỉ được chứa longitude (kinh độ)", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte chỉ được chứa ký tự multibyte", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII chỉ được chứa ký tự ASCII", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII chỉ được chứa ký tự ASCII có thể in ấn", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID phải là giá trị UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3 phải là giá trị UUID phiên bản 3", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4 phải là giá trị UUID phiên bản 4", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5 phải là giá trị UUID phiên bản 5", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN phải là số ISBN", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10 phải là số ISBN-10", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13 phải là số ISBN-13", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes không được chứa chuỗi 'text'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll không được chứa bất kỳ ký tự nào trong nhóm ký tự '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune không được chứa '☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny phải chứa ít nhất 1 trong cách ký tự sau '!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains phải chứa chuỗi 'purpose'", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64 phải là giá trị chuỗi Base64", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email phải là giá trị email address", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL phải là giá trị URL", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI phải là giá trị URI", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString phải là giá trị RGB color", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString phải là giá trị RGBA color", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString phải là giá trị HSL color", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString phải là giá trị HSLA color", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString phải là giá trị hexadecimal", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString phải là giá trị HEX color", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString chỉ được chứa giá trị số", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString chỉ được chứa giá trị số hoặc số dưới dạng chữ", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString chỉ được chứa ký tự dạng alphanumeric", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString chỉ được chứa ký tự dạng alphabetic", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString chỉ được nhỏ hơn MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString chỉ được nhỏ hơn hoặc bằng MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString phải lớn hơn MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString phải lớn hơn hoặc bằng MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString không được phép bằng EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString chỉ được nhỏ hơn Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString chỉ được nhỏ hơn hoặc bằng Inner.LteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString phải lớn hơn Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString phải lớn hơn hoặc bằng Inner.GteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString không được phép bằng Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString phải bằng Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString phải bằng MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString phải có độ dài ít nhất 3 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber phải là 5,56 hoặc lớn hơn", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple phải chứa ít nhất 2 phần tử", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime phải lớn hơn hoặc bằng Ngày & Giờ hiện tại", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString phải có độ dài lớn hơn 3 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber phải lớn hơn 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple phải chứa nhiều hơn 2 phần tử", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime phải lớn hơn Ngày & Giờ hiện tại", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString chỉ được có độ dài tối đa là 3 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber phải là 5,56 hoặc nhỏ hơn", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple chỉ được chứa nhiều nhất 2 phần tử", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime chỉ được nhỏ hơn hoặc bằng Ngày & Giờ hiện tại", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString phải có độ dài nhỏ hơn 3 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber phải nhỏ hơn 5,56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple chỉ được chứa ít hơn 2 phần tử", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime phải nhỏ hơn Ngày & Giờ hiện tại", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString không được bằng ", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber không được bằng 0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple không được bằng 0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString không bằng 3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber không bằng 2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple không bằng 7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString chỉ được chứa tối đa 3 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber phải là 1.113,00 hoặc nhỏ hơn", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple chỉ được chứa tối đa 7 phần tử", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString phải chứa ít nhất 1 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber phải bằng 1.113,00 hoặc lớn hơn", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple phải chứa ít nhất 7 phần tử", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString phải có độ dài là 1 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber phải bằng 1.113,00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple phải chứa 7 phần tử", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString không được bỏ trống", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber không được bỏ trống", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple không được bỏ trống", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen phải chứa ít nhất 10 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen chỉ được chứa tối đa 1 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen phải có độ dài là 2 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt phải có độ dài nhỏ hơn 1 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte chỉ được có độ dài tối đa là 1 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt phải có độ dài lớn hơn 10 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte phải có độ dài ít nhất 10 ký tự", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString phải là trong những giá trị [red green]", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt phải là trong những giá trị [5 63]", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueSlice", |
||||
expected: "UniqueSlice chỉ được chứa những giá trị không trùng lặp", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueArray", |
||||
expected: "UniqueArray chỉ được chứa những giá trị không trùng lặp", |
||||
}, |
||||
{ |
||||
ns: "Test.UniqueMap", |
||||
expected: "UniqueMap chỉ được chứa những giá trị không trùng lặp", |
||||
}, |
||||
{ |
||||
ns: "Test.JSONString", |
||||
expected: "JSONString phải là một chuỗi json hợp lệ", |
||||
}, |
||||
{ |
||||
ns: "Test.JWTString", |
||||
expected: "JWTString phải là một chuỗi jwt hợp lệ", |
||||
}, |
||||
{ |
||||
ns: "Test.LowercaseString", |
||||
expected: "LowercaseString phải được viết thường", |
||||
}, |
||||
{ |
||||
ns: "Test.UppercaseString", |
||||
expected: "UppercaseString phải được viết hoa", |
||||
}, |
||||
{ |
||||
ns: "Test.Datetime", |
||||
expected: "Datetime không trùng định dạng ngày tháng 2006-01-02", |
||||
}, |
||||
{ |
||||
ns: "Test.PostCode", |
||||
expected: "PostCode sai định dạng postcode của quốc gia SG", |
||||
}, |
||||
{ |
||||
ns: "Test.PostCodeByField", |
||||
expected: "PostCodeByField sai định dạng postcode của quốc gia tương ứng thuộc trường PostCodeCountry", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,696 @@ |
||||
package zh |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
zhongwen "github.com/go-playground/locales/zh" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
|
||||
zh := zhongwen.New() |
||||
uni := ut.New(zh, zh) |
||||
trans, _ := uni.GetTranslator("zh") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
AlphanumUnicodeString string `validate:"alphanumunicode"` |
||||
AlphaUnicodeString string `validate:"alphaunicode"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
ContainsRune string `validate:"containsrune=☻"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
EndsWith string `validate:"endswith=end"` |
||||
StartsWith string `validate:"startswith=start"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
JsonString string `validate:"json"` |
||||
LowercaseString string `validate:"lowercase"` |
||||
UppercaseString string `validate:"uppercase"` |
||||
Datetime string `validate:"datetime=2006-01-02"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.AlphanumUnicodeString = "abc3啊!" |
||||
test.AlphaUnicodeString = "abc3啊" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.EndsWith = "this is some test text" |
||||
test.StartsWith = "this is some test text" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
test.JsonString = "{\"foo\":\"bar\",}" |
||||
|
||||
test.LowercaseString = "ABCDEFG" |
||||
test.UppercaseString = "abcdefg" |
||||
|
||||
test.Datetime = "20060102" |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor必须是一个有效的颜色", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC必须是一个有效的MAC地址", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr必须是一个有效的IP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4必须是一个有效的IPv4地址", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6必须是一个有效的IPv6地址", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr必须是一个有效的UDP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4必须是一个有效的IPv4 UDP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6必须是一个有效的IPv6 UDP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr必须是一个有效的TCP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4必须是一个有效的IPv4 TCP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6必须是一个有效的IPv6 TCP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR必须是一个有效的无类别域间路由(CIDR)", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4必须是一个包含IPv4地址的有效无类别域间路由(CIDR)", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6必须是一个包含IPv6地址的有效无类别域间路由(CIDR)", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN必须是一个有效的社会安全号码(SSN)", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP必须是一个有效的IP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4必须是一个有效的IPv4地址", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6必须是一个有效的IPv6地址", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI必须包含有效的数据URI", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude必须包含有效的纬度坐标", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude必须包含有效的经度坐标", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte必须包含多字节字符", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII必须只包含ascii字符", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII必须只包含可打印的ascii字符", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID必须是一个有效的UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3必须是一个有效的V3 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4必须是一个有效的V4 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5必须是一个有效的V5 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID必须是一个有效的ULID", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN必须是一个有效的ISBN编号", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10必须是一个有效的ISBN-10编号", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13必须是一个有效的ISBN-13编号", |
||||
}, |
||||
{ |
||||
ns: "Test.EndsWith", |
||||
expected: "EndsWith必须以文本'end'结尾", |
||||
}, |
||||
{ |
||||
ns: "Test.StartsWith", |
||||
expected: "StartsWith必须以文本'start'开头", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes不能包含文本'text'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll不能包含以下任何字符'!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune不能包含'☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsRune", |
||||
expected: "ContainsRune必须包含字符'☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny必须包含至少一个以下字符'!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains必须包含文本'purpose'", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64必须是一个有效的Base64字符串", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email必须是一个有效的邮箱", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL必须是一个有效的URL", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI必须是一个有效的URI", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString必须是一个有效的RGB颜色", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString必须是一个有效的RGBA颜色", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString必须是一个有效的HSL颜色", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString必须是一个有效的HSLA颜色", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString必须是一个有效的十六进制", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString必须是一个有效的十六进制颜色", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString必须是一个有效的数字", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString必须是一个有效的数值", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaUnicodeString", |
||||
expected: "AlphaUnicodeString只能包含字母和Unicode字符", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumUnicodeString", |
||||
expected: "AlphanumUnicodeString只能包含字母数字和Unicode字符", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString只能包含字母和数字", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString只能包含字母", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString必须小于MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString必须小于或等于MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString必须大于MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString必须大于或等于MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString不能等于EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString必须小于Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString必须小于或等于Inner.LteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString必须大于Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString必须大于或等于Inner.GteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString不能等于Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString必须等于Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString必须等于MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString长度必须至少为3个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber必须大于或等于5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple必须至少包含2项", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime必须大于或等于当前日期和时间", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString长度必须大于3个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber必须大于5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple必须大于2项", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime必须大于当前日期和时间", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString长度不能超过3个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber必须小于或等于5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple最多只能包含2项", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime必须小于或等于当前日期和时间", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString长度必须小于3个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber必须小于5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple必须包含少于2项", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime必须小于当前日期和时间", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString不能等于", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber不能等于0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple不能等于0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString不等于3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber不等于2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple不等于7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString长度不能超过3个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber必须小于或等于1,113.00", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple最多只能包含7项", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString长度必须至少为1个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber最小只能为1,113.00", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple必须至少包含7项", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString长度必须是1个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber必须等于1,113.00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple必须包含7项", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString为必填字段", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber为必填字段", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple为必填字段", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen长度必须至少为10个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen长度不能超过1个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen长度必须是2个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt长度必须小于1个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte长度不能超过1个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt长度必须大于10个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte长度必须至少为10个字符", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString必须是[red green]中的一个", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt必须是[5 63]中的一个", |
||||
}, |
||||
{ |
||||
ns: "Test.JsonString", |
||||
expected: "JsonString必须是一个JSON字符串", |
||||
}, |
||||
{ |
||||
ns: "Test.LowercaseString", |
||||
expected: "LowercaseString必须是小写字母", |
||||
}, |
||||
{ |
||||
ns: "Test.UppercaseString", |
||||
expected: "UppercaseString必须是大写字母", |
||||
}, |
||||
{ |
||||
ns: "Test.Datetime", |
||||
expected: "Datetime的格式必须是2006-01-02", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,646 @@ |
||||
package zh_tw |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
. "github.com/go-playground/assert/v2" |
||||
zhongwen "github.com/go-playground/locales/zh_Hant_TW" |
||||
ut "github.com/go-playground/universal-translator" |
||||
"github.com/go-playground/validator/v10" |
||||
) |
||||
|
||||
func TestTranslations(t *testing.T) { |
||||
|
||||
zh := zhongwen.New() |
||||
uni := ut.New(zh, zh) |
||||
trans, _ := uni.GetTranslator("zh") |
||||
|
||||
validate := validator.New() |
||||
|
||||
err := RegisterDefaultTranslations(validate, trans) |
||||
Equal(t, err, nil) |
||||
|
||||
type Inner struct { |
||||
EqCSFieldString string |
||||
NeCSFieldString string |
||||
GtCSFieldString string |
||||
GteCSFieldString string |
||||
LtCSFieldString string |
||||
LteCSFieldString string |
||||
} |
||||
|
||||
type Test struct { |
||||
Inner Inner |
||||
RequiredString string `validate:"required"` |
||||
RequiredNumber int `validate:"required"` |
||||
RequiredMultiple []string `validate:"required"` |
||||
LenString string `validate:"len=1"` |
||||
LenNumber float64 `validate:"len=1113.00"` |
||||
LenMultiple []string `validate:"len=7"` |
||||
MinString string `validate:"min=1"` |
||||
MinNumber float64 `validate:"min=1113.00"` |
||||
MinMultiple []string `validate:"min=7"` |
||||
MaxString string `validate:"max=3"` |
||||
MaxNumber float64 `validate:"max=1113.00"` |
||||
MaxMultiple []string `validate:"max=7"` |
||||
EqString string `validate:"eq=3"` |
||||
EqNumber float64 `validate:"eq=2.33"` |
||||
EqMultiple []string `validate:"eq=7"` |
||||
NeString string `validate:"ne="` |
||||
NeNumber float64 `validate:"ne=0.00"` |
||||
NeMultiple []string `validate:"ne=0"` |
||||
LtString string `validate:"lt=3"` |
||||
LtNumber float64 `validate:"lt=5.56"` |
||||
LtMultiple []string `validate:"lt=2"` |
||||
LtTime time.Time `validate:"lt"` |
||||
LteString string `validate:"lte=3"` |
||||
LteNumber float64 `validate:"lte=5.56"` |
||||
LteMultiple []string `validate:"lte=2"` |
||||
LteTime time.Time `validate:"lte"` |
||||
GtString string `validate:"gt=3"` |
||||
GtNumber float64 `validate:"gt=5.56"` |
||||
GtMultiple []string `validate:"gt=2"` |
||||
GtTime time.Time `validate:"gt"` |
||||
GteString string `validate:"gte=3"` |
||||
GteNumber float64 `validate:"gte=5.56"` |
||||
GteMultiple []string `validate:"gte=2"` |
||||
GteTime time.Time `validate:"gte"` |
||||
EqFieldString string `validate:"eqfield=MaxString"` |
||||
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` |
||||
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` |
||||
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` |
||||
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` |
||||
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` |
||||
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` |
||||
NeFieldString string `validate:"nefield=EqFieldString"` |
||||
GtFieldString string `validate:"gtfield=MaxString"` |
||||
GteFieldString string `validate:"gtefield=MaxString"` |
||||
LtFieldString string `validate:"ltfield=MaxString"` |
||||
LteFieldString string `validate:"ltefield=MaxString"` |
||||
AlphaString string `validate:"alpha"` |
||||
AlphanumString string `validate:"alphanum"` |
||||
NumericString string `validate:"numeric"` |
||||
NumberString string `validate:"number"` |
||||
HexadecimalString string `validate:"hexadecimal"` |
||||
HexColorString string `validate:"hexcolor"` |
||||
RGBColorString string `validate:"rgb"` |
||||
RGBAColorString string `validate:"rgba"` |
||||
HSLColorString string `validate:"hsl"` |
||||
HSLAColorString string `validate:"hsla"` |
||||
Email string `validate:"email"` |
||||
URL string `validate:"url"` |
||||
URI string `validate:"uri"` |
||||
Base64 string `validate:"base64"` |
||||
Contains string `validate:"contains=purpose"` |
||||
ContainsAny string `validate:"containsany=!@#$"` |
||||
Excludes string `validate:"excludes=text"` |
||||
ExcludesAll string `validate:"excludesall=!@#$"` |
||||
ExcludesRune string `validate:"excludesrune=☻"` |
||||
ISBN string `validate:"isbn"` |
||||
ISBN10 string `validate:"isbn10"` |
||||
ISBN13 string `validate:"isbn13"` |
||||
UUID string `validate:"uuid"` |
||||
UUID3 string `validate:"uuid3"` |
||||
UUID4 string `validate:"uuid4"` |
||||
UUID5 string `validate:"uuid5"` |
||||
ULID string `validate:"ulid"` |
||||
ASCII string `validate:"ascii"` |
||||
PrintableASCII string `validate:"printascii"` |
||||
MultiByte string `validate:"multibyte"` |
||||
DataURI string `validate:"datauri"` |
||||
Latitude string `validate:"latitude"` |
||||
Longitude string `validate:"longitude"` |
||||
SSN string `validate:"ssn"` |
||||
IP string `validate:"ip"` |
||||
IPv4 string `validate:"ipv4"` |
||||
IPv6 string `validate:"ipv6"` |
||||
CIDR string `validate:"cidr"` |
||||
CIDRv4 string `validate:"cidrv4"` |
||||
CIDRv6 string `validate:"cidrv6"` |
||||
TCPAddr string `validate:"tcp_addr"` |
||||
TCPAddrv4 string `validate:"tcp4_addr"` |
||||
TCPAddrv6 string `validate:"tcp6_addr"` |
||||
UDPAddr string `validate:"udp_addr"` |
||||
UDPAddrv4 string `validate:"udp4_addr"` |
||||
UDPAddrv6 string `validate:"udp6_addr"` |
||||
IPAddr string `validate:"ip_addr"` |
||||
IPAddrv4 string `validate:"ip4_addr"` |
||||
IPAddrv6 string `validate:"ip6_addr"` |
||||
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
|
||||
MAC string `validate:"mac"` |
||||
IsColor string `validate:"iscolor"` |
||||
StrPtrMinLen *string `validate:"min=10"` |
||||
StrPtrMaxLen *string `validate:"max=1"` |
||||
StrPtrLen *string `validate:"len=2"` |
||||
StrPtrLt *string `validate:"lt=1"` |
||||
StrPtrLte *string `validate:"lte=1"` |
||||
StrPtrGt *string `validate:"gt=10"` |
||||
StrPtrGte *string `validate:"gte=10"` |
||||
OneOfString string `validate:"oneof=red green"` |
||||
OneOfInt int `validate:"oneof=5 63"` |
||||
Datetime string `validate:"datetime=2006-01-02"` |
||||
} |
||||
|
||||
var test Test |
||||
|
||||
test.Inner.EqCSFieldString = "1234" |
||||
test.Inner.GtCSFieldString = "1234" |
||||
test.Inner.GteCSFieldString = "1234" |
||||
|
||||
test.MaxString = "1234" |
||||
test.MaxNumber = 2000 |
||||
test.MaxMultiple = make([]string, 9) |
||||
|
||||
test.LtString = "1234" |
||||
test.LtNumber = 6 |
||||
test.LtMultiple = make([]string, 3) |
||||
test.LtTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LteString = "1234" |
||||
test.LteNumber = 6 |
||||
test.LteMultiple = make([]string, 3) |
||||
test.LteTime = time.Now().Add(time.Hour * 24) |
||||
|
||||
test.LtFieldString = "12345" |
||||
test.LteFieldString = "12345" |
||||
|
||||
test.LtCSFieldString = "1234" |
||||
test.LteCSFieldString = "1234" |
||||
|
||||
test.AlphaString = "abc3" |
||||
test.AlphanumString = "abc3!" |
||||
test.NumericString = "12E.00" |
||||
test.NumberString = "12E" |
||||
|
||||
test.Excludes = "this is some test text" |
||||
test.ExcludesAll = "This is Great!" |
||||
test.ExcludesRune = "Love it ☻" |
||||
|
||||
test.ASCII = "カタカナ" |
||||
test.PrintableASCII = "カタカナ" |
||||
|
||||
test.MultiByte = "1234feerf" |
||||
|
||||
s := "toolong" |
||||
test.StrPtrMaxLen = &s |
||||
test.StrPtrLen = &s |
||||
|
||||
test.Datetime = "2008-Feb-01" |
||||
|
||||
err = validate.Struct(test) |
||||
NotEqual(t, err, nil) |
||||
|
||||
errs, ok := err.(validator.ValidationErrors) |
||||
Equal(t, ok, true) |
||||
|
||||
tests := []struct { |
||||
ns string |
||||
expected string |
||||
}{ |
||||
{ |
||||
ns: "Test.IsColor", |
||||
expected: "IsColor必須是一個有效的顏色", |
||||
}, |
||||
{ |
||||
ns: "Test.MAC", |
||||
expected: "MAC必須是一個有效的MAC地址", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddr", |
||||
expected: "IPAddr必須是一個有效的IP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv4", |
||||
expected: "IPAddrv4必須是一個有效的IPv4地址", |
||||
}, |
||||
{ |
||||
ns: "Test.IPAddrv6", |
||||
expected: "IPAddrv6必須是一個有效的IPv6地址", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddr", |
||||
expected: "UDPAddr必須是一個有效的UDP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv4", |
||||
expected: "UDPAddrv4必須是一個有效的IPv4 UDP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.UDPAddrv6", |
||||
expected: "UDPAddrv6必須是一個有效的IPv6 UDP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddr", |
||||
expected: "TCPAddr必須是一個有效的TCP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv4", |
||||
expected: "TCPAddrv4必須是一個有效的IPv4 TCP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.TCPAddrv6", |
||||
expected: "TCPAddrv6必須是一個有效的IPv6 TCP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDR", |
||||
expected: "CIDR必須是一個有效的無類別域間路由(CIDR)", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv4", |
||||
expected: "CIDRv4必須是一个包含IPv4地址的有效無類別域間路由(CIDR)", |
||||
}, |
||||
{ |
||||
ns: "Test.CIDRv6", |
||||
expected: "CIDRv6必須是一个包含IPv6地址的有效無類別域間路由(CIDR)", |
||||
}, |
||||
{ |
||||
ns: "Test.SSN", |
||||
expected: "SSN必須是一個有效的社會安全編號(SSN)", |
||||
}, |
||||
{ |
||||
ns: "Test.IP", |
||||
expected: "IP必須是一個有效的IP地址", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv4", |
||||
expected: "IPv4必須是一個有效的IPv4地址", |
||||
}, |
||||
{ |
||||
ns: "Test.IPv6", |
||||
expected: "IPv6必須是一個有效的IPv6地址", |
||||
}, |
||||
{ |
||||
ns: "Test.DataURI", |
||||
expected: "DataURI必須包含有效的數據URI", |
||||
}, |
||||
{ |
||||
ns: "Test.Latitude", |
||||
expected: "Latitude必須包含有效的緯度座標", |
||||
}, |
||||
{ |
||||
ns: "Test.Longitude", |
||||
expected: "Longitude必須包含有效的經度座標", |
||||
}, |
||||
{ |
||||
ns: "Test.MultiByte", |
||||
expected: "MultiByte必須包含多個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.ASCII", |
||||
expected: "ASCII必須只包含ascii字元", |
||||
}, |
||||
{ |
||||
ns: "Test.PrintableASCII", |
||||
expected: "PrintableASCII必須只包含可輸出的ascii字元", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID", |
||||
expected: "UUID必須是一個有效的UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID3", |
||||
expected: "UUID3必須是一個有效的V3 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID4", |
||||
expected: "UUID4必須是一個有效的V4 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.UUID5", |
||||
expected: "UUID5必須是一個有效的V5 UUID", |
||||
}, |
||||
{ |
||||
ns: "Test.ULID", |
||||
expected: "ULID必須是一個有效的ULID", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN", |
||||
expected: "ISBN必須是一個有效的ISBN編號", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN10", |
||||
expected: "ISBN10必須是一個有效的ISBN-10編號", |
||||
}, |
||||
{ |
||||
ns: "Test.ISBN13", |
||||
expected: "ISBN13必須是一個有效的ISBN-13編號", |
||||
}, |
||||
{ |
||||
ns: "Test.Excludes", |
||||
expected: "Excludes不能包含文字'text'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesAll", |
||||
expected: "ExcludesAll不能包含以下任何字元'!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.ExcludesRune", |
||||
expected: "ExcludesRune不能包含'☻'", |
||||
}, |
||||
{ |
||||
ns: "Test.ContainsAny", |
||||
expected: "ContainsAny必須包含至少一個以下字元'!@#$'", |
||||
}, |
||||
{ |
||||
ns: "Test.Contains", |
||||
expected: "Contains必須包含文字'purpose'", |
||||
}, |
||||
{ |
||||
ns: "Test.Base64", |
||||
expected: "Base64必須是一個有效的Base64字元串", |
||||
}, |
||||
{ |
||||
ns: "Test.Email", |
||||
expected: "Email必須是一個有效的信箱", |
||||
}, |
||||
{ |
||||
ns: "Test.URL", |
||||
expected: "URL必須是一個有效的URL", |
||||
}, |
||||
{ |
||||
ns: "Test.URI", |
||||
expected: "URI必須是一個有效的URI", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBColorString", |
||||
expected: "RGBColorString必須是一個有效的RGB顏色", |
||||
}, |
||||
{ |
||||
ns: "Test.RGBAColorString", |
||||
expected: "RGBAColorString必須是一個有效的RGBA顏色", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLColorString", |
||||
expected: "HSLColorString必須是一個有效的HSL顏色", |
||||
}, |
||||
{ |
||||
ns: "Test.HSLAColorString", |
||||
expected: "HSLAColorString必須是一個有效的HSLA顏色", |
||||
}, |
||||
{ |
||||
ns: "Test.HexadecimalString", |
||||
expected: "HexadecimalString必須是一個有效的十六進制", |
||||
}, |
||||
{ |
||||
ns: "Test.HexColorString", |
||||
expected: "HexColorString必須是一個有效的十六進制顏色", |
||||
}, |
||||
{ |
||||
ns: "Test.NumberString", |
||||
expected: "NumberString必須是一個有效的數字", |
||||
}, |
||||
{ |
||||
ns: "Test.NumericString", |
||||
expected: "NumericString必須是一個有效的數值", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphanumString", |
||||
expected: "AlphanumString只能包含字母和數字", |
||||
}, |
||||
{ |
||||
ns: "Test.AlphaString", |
||||
expected: "AlphaString只能包含字母", |
||||
}, |
||||
{ |
||||
ns: "Test.LtFieldString", |
||||
expected: "LtFieldString必須小於MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteFieldString", |
||||
expected: "LteFieldString必須小於或等於MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtFieldString", |
||||
expected: "GtFieldString必須大於MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteFieldString", |
||||
expected: "GteFieldString必須大於或等於MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeFieldString", |
||||
expected: "NeFieldString不能等於EqFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LtCSFieldString", |
||||
expected: "LtCSFieldString必須小於Inner.LtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.LteCSFieldString", |
||||
expected: "LteCSFieldString必須小於或等於Inner.LteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GtCSFieldString", |
||||
expected: "GtCSFieldString必須大於Inner.GtCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteCSFieldString", |
||||
expected: "GteCSFieldString必須大於或等於Inner.GteCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.NeCSFieldString", |
||||
expected: "NeCSFieldString不能等於Inner.NeCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqCSFieldString", |
||||
expected: "EqCSFieldString必須等於Inner.EqCSFieldString", |
||||
}, |
||||
{ |
||||
ns: "Test.EqFieldString", |
||||
expected: "EqFieldString必須等於MaxString", |
||||
}, |
||||
{ |
||||
ns: "Test.GteString", |
||||
expected: "GteString長度必須至少為3個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.GteNumber", |
||||
expected: "GteNumber必須大於或等於5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.GteMultiple", |
||||
expected: "GteMultiple必須至少包含2項", |
||||
}, |
||||
{ |
||||
ns: "Test.GteTime", |
||||
expected: "GteTime必須大於或等於目前日期和時間", |
||||
}, |
||||
{ |
||||
ns: "Test.GtString", |
||||
expected: "GtString長度必須大於3個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.GtNumber", |
||||
expected: "GtNumber必須大於5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.GtMultiple", |
||||
expected: "GtMultiple必須大於2項", |
||||
}, |
||||
{ |
||||
ns: "Test.GtTime", |
||||
expected: "GtTime必須大於目前日期和時間", |
||||
}, |
||||
{ |
||||
ns: "Test.LteString", |
||||
expected: "LteString長度不能超過3個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.LteNumber", |
||||
expected: "LteNumber必須小於或等於5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.LteMultiple", |
||||
expected: "LteMultiple最多只能包含2項", |
||||
}, |
||||
{ |
||||
ns: "Test.LteTime", |
||||
expected: "LteTime必須小於或等於目前日期和時間", |
||||
}, |
||||
{ |
||||
ns: "Test.LtString", |
||||
expected: "LtString長度必須小於3個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.LtNumber", |
||||
expected: "LtNumber必須小於5.56", |
||||
}, |
||||
{ |
||||
ns: "Test.LtMultiple", |
||||
expected: "LtMultiple必須包含少於2項", |
||||
}, |
||||
{ |
||||
ns: "Test.LtTime", |
||||
expected: "LtTime必須小於目前日期和時間", |
||||
}, |
||||
{ |
||||
ns: "Test.NeString", |
||||
expected: "NeString不能等於", |
||||
}, |
||||
{ |
||||
ns: "Test.NeNumber", |
||||
expected: "NeNumber不能等於0.00", |
||||
}, |
||||
{ |
||||
ns: "Test.NeMultiple", |
||||
expected: "NeMultiple不能等於0", |
||||
}, |
||||
{ |
||||
ns: "Test.EqString", |
||||
expected: "EqString不等於3", |
||||
}, |
||||
{ |
||||
ns: "Test.EqNumber", |
||||
expected: "EqNumber不等於2.33", |
||||
}, |
||||
{ |
||||
ns: "Test.EqMultiple", |
||||
expected: "EqMultiple不等於7", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxString", |
||||
expected: "MaxString長度不能超過3個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxNumber", |
||||
expected: "MaxNumber必須小於或等於1,113.00", |
||||
}, |
||||
{ |
||||
ns: "Test.MaxMultiple", |
||||
expected: "MaxMultiple最多只能包含7項", |
||||
}, |
||||
{ |
||||
ns: "Test.MinString", |
||||
expected: "MinString長度必須至少為1個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.MinNumber", |
||||
expected: "MinNumber最小只能為1,113.00", |
||||
}, |
||||
{ |
||||
ns: "Test.MinMultiple", |
||||
expected: "MinMultiple必須至少包含7項", |
||||
}, |
||||
{ |
||||
ns: "Test.LenString", |
||||
expected: "LenString長度必須為1個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.LenNumber", |
||||
expected: "LenNumber必須等於1,113.00", |
||||
}, |
||||
{ |
||||
ns: "Test.LenMultiple", |
||||
expected: "LenMultiple必須包含7項", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredString", |
||||
expected: "RequiredString為必填欄位", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredNumber", |
||||
expected: "RequiredNumber為必填欄位", |
||||
}, |
||||
{ |
||||
ns: "Test.RequiredMultiple", |
||||
expected: "RequiredMultiple為必填欄位", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMinLen", |
||||
expected: "StrPtrMinLen長度必須至少為10個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrMaxLen", |
||||
expected: "StrPtrMaxLen長度不能超過1個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLen", |
||||
expected: "StrPtrLen長度必須為2個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLt", |
||||
expected: "StrPtrLt長度必須小於1個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrLte", |
||||
expected: "StrPtrLte長度不能超過1個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGt", |
||||
expected: "StrPtrGt長度必須大於10個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.StrPtrGte", |
||||
expected: "StrPtrGte長度必須至少為10個字元", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfString", |
||||
expected: "OneOfString必須是[red green]中的一個", |
||||
}, |
||||
{ |
||||
ns: "Test.OneOfInt", |
||||
expected: "OneOfInt必須是[5 63]中的一個", |
||||
}, |
||||
{ |
||||
ns: "Test.Datetime", |
||||
expected: "Datetime與2006-01-02格式不匹配", |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
|
||||
var fe validator.FieldError |
||||
|
||||
for _, e := range errs { |
||||
if tt.ns == e.Namespace() { |
||||
fe = e |
||||
break |
||||
} |
||||
} |
||||
|
||||
NotEqual(t, fe, nil) |
||||
Equal(t, tt.expected, fe.Translate(trans)) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,288 @@ |
||||
package validator |
||||
|
||||
import ( |
||||
"reflect" |
||||
"strconv" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
// extractTypeInternal gets the actual underlying type of field value.
|
||||
// It will dive into pointers, customTypes and return you the
|
||||
// underlying value and it's kind.
|
||||
func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) { |
||||
|
||||
BEGIN: |
||||
switch current.Kind() { |
||||
case reflect.Ptr: |
||||
|
||||
nullable = true |
||||
|
||||
if current.IsNil() { |
||||
return current, reflect.Ptr, nullable |
||||
} |
||||
|
||||
current = current.Elem() |
||||
goto BEGIN |
||||
|
||||
case reflect.Interface: |
||||
|
||||
nullable = true |
||||
|
||||
if current.IsNil() { |
||||
return current, reflect.Interface, nullable |
||||
} |
||||
|
||||
current = current.Elem() |
||||
goto BEGIN |
||||
|
||||
case reflect.Invalid: |
||||
return current, reflect.Invalid, nullable |
||||
|
||||
default: |
||||
|
||||
if v.v.hasCustomFuncs { |
||||
|
||||
if fn, ok := v.v.customFuncs[current.Type()]; ok { |
||||
current = reflect.ValueOf(fn(current)) |
||||
goto BEGIN |
||||
} |
||||
} |
||||
|
||||
return current, current.Kind(), nullable |
||||
} |
||||
} |
||||
|
||||
// getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and
|
||||
// returns the field, field kind and whether is was successful in retrieving the field at all.
|
||||
//
|
||||
// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
|
||||
// could not be retrieved because it didn't exist.
|
||||
func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, nullable bool, found bool) { |
||||
|
||||
BEGIN: |
||||
current, kind, nullable = v.ExtractType(val) |
||||
if kind == reflect.Invalid { |
||||
return |
||||
} |
||||
|
||||
if namespace == "" { |
||||
found = true |
||||
return |
||||
} |
||||
|
||||
switch kind { |
||||
|
||||
case reflect.Ptr, reflect.Interface: |
||||
return |
||||
|
||||
case reflect.Struct: |
||||
|
||||
typ := current.Type() |
||||
fld := namespace |
||||
var ns string |
||||
|
||||
if !typ.ConvertibleTo(timeType) { |
||||
|
||||
idx := strings.Index(namespace, namespaceSeparator) |
||||
|
||||
if idx != -1 { |
||||
fld = namespace[:idx] |
||||
ns = namespace[idx+1:] |
||||
} else { |
||||
ns = "" |
||||
} |
||||
|
||||
bracketIdx := strings.Index(fld, leftBracket) |
||||
if bracketIdx != -1 { |
||||
fld = fld[:bracketIdx] |
||||
|
||||
ns = namespace[bracketIdx:] |
||||
} |
||||
|
||||
val = current.FieldByName(fld) |
||||
namespace = ns |
||||
goto BEGIN |
||||
} |
||||
|
||||
case reflect.Array, reflect.Slice: |
||||
idx := strings.Index(namespace, leftBracket) |
||||
idx2 := strings.Index(namespace, rightBracket) |
||||
|
||||
arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2]) |
||||
|
||||
if arrIdx >= current.Len() { |
||||
return |
||||
} |
||||
|
||||
startIdx := idx2 + 1 |
||||
|
||||
if startIdx < len(namespace) { |
||||
if namespace[startIdx:startIdx+1] == namespaceSeparator { |
||||
startIdx++ |
||||
} |
||||
} |
||||
|
||||
val = current.Index(arrIdx) |
||||
namespace = namespace[startIdx:] |
||||
goto BEGIN |
||||
|
||||
case reflect.Map: |
||||
idx := strings.Index(namespace, leftBracket) + 1 |
||||
idx2 := strings.Index(namespace, rightBracket) |
||||
|
||||
endIdx := idx2 |
||||
|
||||
if endIdx+1 < len(namespace) { |
||||
if namespace[endIdx+1:endIdx+2] == namespaceSeparator { |
||||
endIdx++ |
||||
} |
||||
} |
||||
|
||||
key := namespace[idx:idx2] |
||||
|
||||
switch current.Type().Key().Kind() { |
||||
case reflect.Int: |
||||
i, _ := strconv.Atoi(key) |
||||
val = current.MapIndex(reflect.ValueOf(i)) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Int8: |
||||
i, _ := strconv.ParseInt(key, 10, 8) |
||||
val = current.MapIndex(reflect.ValueOf(int8(i))) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Int16: |
||||
i, _ := strconv.ParseInt(key, 10, 16) |
||||
val = current.MapIndex(reflect.ValueOf(int16(i))) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Int32: |
||||
i, _ := strconv.ParseInt(key, 10, 32) |
||||
val = current.MapIndex(reflect.ValueOf(int32(i))) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Int64: |
||||
i, _ := strconv.ParseInt(key, 10, 64) |
||||
val = current.MapIndex(reflect.ValueOf(i)) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Uint: |
||||
i, _ := strconv.ParseUint(key, 10, 0) |
||||
val = current.MapIndex(reflect.ValueOf(uint(i))) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Uint8: |
||||
i, _ := strconv.ParseUint(key, 10, 8) |
||||
val = current.MapIndex(reflect.ValueOf(uint8(i))) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Uint16: |
||||
i, _ := strconv.ParseUint(key, 10, 16) |
||||
val = current.MapIndex(reflect.ValueOf(uint16(i))) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Uint32: |
||||
i, _ := strconv.ParseUint(key, 10, 32) |
||||
val = current.MapIndex(reflect.ValueOf(uint32(i))) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Uint64: |
||||
i, _ := strconv.ParseUint(key, 10, 64) |
||||
val = current.MapIndex(reflect.ValueOf(i)) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Float32: |
||||
f, _ := strconv.ParseFloat(key, 32) |
||||
val = current.MapIndex(reflect.ValueOf(float32(f))) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Float64: |
||||
f, _ := strconv.ParseFloat(key, 64) |
||||
val = current.MapIndex(reflect.ValueOf(f)) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
case reflect.Bool: |
||||
b, _ := strconv.ParseBool(key) |
||||
val = current.MapIndex(reflect.ValueOf(b)) |
||||
namespace = namespace[endIdx+1:] |
||||
|
||||
// reflect.Type = string
|
||||
default: |
||||
val = current.MapIndex(reflect.ValueOf(key)) |
||||
namespace = namespace[endIdx+1:] |
||||
} |
||||
|
||||
goto BEGIN |
||||
} |
||||
|
||||
// if got here there was more namespace, cannot go any deeper
|
||||
panic("Invalid field namespace") |
||||
} |
||||
|
||||
// asInt returns the parameter as a int64
|
||||
// or panics if it can't convert
|
||||
func asInt(param string) int64 { |
||||
i, err := strconv.ParseInt(param, 0, 64) |
||||
panicIf(err) |
||||
|
||||
return i |
||||
} |
||||
|
||||
// asIntFromTimeDuration parses param as time.Duration and returns it as int64
|
||||
// or panics on error.
|
||||
func asIntFromTimeDuration(param string) int64 { |
||||
d, err := time.ParseDuration(param) |
||||
if err != nil { |
||||
// attempt parsing as an an integer assuming nanosecond precision
|
||||
return asInt(param) |
||||
} |
||||
return int64(d) |
||||
} |
||||
|
||||
// asIntFromType calls the proper function to parse param as int64,
|
||||
// given a field's Type t.
|
||||
func asIntFromType(t reflect.Type, param string) int64 { |
||||
switch t { |
||||
case timeDurationType: |
||||
return asIntFromTimeDuration(param) |
||||
default: |
||||
return asInt(param) |
||||
} |
||||
} |
||||
|
||||
// asUint returns the parameter as a uint64
|
||||
// or panics if it can't convert
|
||||
func asUint(param string) uint64 { |
||||
|
||||
i, err := strconv.ParseUint(param, 0, 64) |
||||
panicIf(err) |
||||
|
||||
return i |
||||
} |
||||
|
||||
// asFloat returns the parameter as a float64
|
||||
// or panics if it can't convert
|
||||
func asFloat(param string) float64 { |
||||
|
||||
i, err := strconv.ParseFloat(param, 64) |
||||
panicIf(err) |
||||
|
||||
return i |
||||
} |
||||
|
||||
// asBool returns the parameter as a bool
|
||||
// or panics if it can't convert
|
||||
func asBool(param string) bool { |
||||
|
||||
i, err := strconv.ParseBool(param) |
||||
panicIf(err) |
||||
|
||||
return i |
||||
} |
||||
|
||||
func panicIf(err error) { |
||||
if err != nil { |
||||
panic(err.Error()) |
||||
} |
||||
} |
@ -1,375 +1,485 @@ |
||||
/** |
||||
* Package validator |
||||
* |
||||
* MISC: |
||||
* - anonymous structs - they don't have names so expect the Struct name within StructValidationErrors to be blank |
||||
* |
||||
*/ |
||||
|
||||
package validator |
||||
|
||||
import ( |
||||
"bytes" |
||||
"errors" |
||||
"context" |
||||
"fmt" |
||||
"reflect" |
||||
"strings" |
||||
"time" |
||||
"unicode" |
||||
) |
||||
|
||||
const ( |
||||
tagSeparator = "," |
||||
orSeparator = "|" |
||||
noValidationTag = "-" |
||||
tagKeySeparator = "=" |
||||
structOnlyTag = "structonly" |
||||
omitempty = "omitempty" |
||||
validationFieldErrMsg = "Field validation for \"%s\" failed on the \"%s\" tag\n" |
||||
validationStructErrMsg = "Struct:%s\n" |
||||
"strconv" |
||||
) |
||||
|
||||
// FieldValidationError contains a single field's validation error along
|
||||
// with other properties that may be needed for error message creation
|
||||
type FieldValidationError struct { |
||||
Field string |
||||
ErrorTag string |
||||
Kind reflect.Kind |
||||
Type reflect.Type |
||||
Param string |
||||
Value interface{} |
||||
// per validate construct
|
||||
type validate struct { |
||||
v *Validate |
||||
top reflect.Value |
||||
ns []byte |
||||
actualNs []byte |
||||
errs ValidationErrors |
||||
includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise
|
||||
ffn FilterFunc |
||||
slflParent reflect.Value // StructLevel & FieldLevel
|
||||
slCurrent reflect.Value // StructLevel & FieldLevel
|
||||
flField reflect.Value // StructLevel & FieldLevel
|
||||
cf *cField // StructLevel & FieldLevel
|
||||
ct *cTag // StructLevel & FieldLevel
|
||||
misc []byte // misc reusable
|
||||
str1 string // misc reusable
|
||||
str2 string // misc reusable
|
||||
fldIsPointer bool // StructLevel & FieldLevel
|
||||
isPartial bool |
||||
hasExcludes bool |
||||
} |
||||
|
||||
// parent and current will be the same the first run of validateStruct
|
||||
func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) { |
||||
|
||||
cs, ok := v.v.structCache.Get(typ) |
||||
if !ok { |
||||
cs = v.v.extractStructCache(current, typ.Name()) |
||||
} |
||||
|
||||
// This is intended for use in development + debugging and not intended to be a production error message.
|
||||
// it also allows FieldValidationError to be used as an Error interface
|
||||
func (e *FieldValidationError) Error() string { |
||||
return fmt.Sprintf(validationFieldErrMsg, e.Field, e.ErrorTag) |
||||
} |
||||
if len(ns) == 0 && len(cs.name) != 0 { |
||||
|
||||
// StructValidationErrors is hierarchical list of field and struct validation errors
|
||||
// for a non hierarchical representation please see the Flatten method for StructValidationErrors
|
||||
type StructValidationErrors struct { |
||||
// Name of the Struct
|
||||
Struct string |
||||
// Struct Field Errors
|
||||
Errors map[string]*FieldValidationError |
||||
// Struct Fields of type struct and their errors
|
||||
// key = Field Name of current struct, but internally Struct will be the actual struct name unless anonymous struct, it will be blank
|
||||
StructErrors map[string]*StructValidationErrors |
||||
} |
||||
ns = append(ns, cs.name...) |
||||
ns = append(ns, '.') |
||||
|
||||
// This is intended for use in development + debugging and not intended to be a production error message.
|
||||
// it also allows StructValidationErrors to be used as an Error interface
|
||||
func (e *StructValidationErrors) Error() string { |
||||
buff := bytes.NewBufferString(fmt.Sprintf(validationStructErrMsg, e.Struct)) |
||||
|
||||
for _, err := range e.Errors { |
||||
buff.WriteString(err.Error()) |
||||
structNs = append(structNs, cs.name...) |
||||
structNs = append(structNs, '.') |
||||
} |
||||
|
||||
for _, err := range e.StructErrors { |
||||
buff.WriteString(err.Error()) |
||||
} |
||||
buff.WriteString("\n\n") |
||||
return buff.String() |
||||
} |
||||
// ct is nil on top level struct, and structs as fields that have no tag info
|
||||
// so if nil or if not nil and the structonly tag isn't present
|
||||
if ct == nil || ct.typeof != typeStructOnly { |
||||
|
||||
// Flatten flattens the StructValidationErrors hierarchical structure into a flat namespace style field name
|
||||
// for those that want/need it
|
||||
func (e *StructValidationErrors) Flatten() map[string]*FieldValidationError { |
||||
var f *cField |
||||
|
||||
if e == nil { |
||||
return nil |
||||
} |
||||
for i := 0; i < len(cs.fields); i++ { |
||||
|
||||
errs := map[string]*FieldValidationError{} |
||||
f = cs.fields[i] |
||||
|
||||
for _, f := range e.Errors { |
||||
if v.isPartial { |
||||
|
||||
errs[f.Field] = f |
||||
if v.ffn != nil { |
||||
// used with StructFiltered
|
||||
if v.ffn(append(structNs, f.name...)) { |
||||
continue |
||||
} |
||||
|
||||
for key, val := range e.StructErrors { |
||||
|
||||
otherErrs := val.Flatten() |
||||
|
||||
for _, f2 := range otherErrs { |
||||
} else { |
||||
// used with StructPartial & StructExcept
|
||||
_, ok = v.includeExclude[string(append(structNs, f.name...))] |
||||
|
||||
f2.Field = fmt.Sprintf("%s.%s", key, f2.Field) |
||||
errs[f2.Field] = f2 |
||||
if (ok && v.hasExcludes) || (!ok && !v.hasExcludes) { |
||||
continue |
||||
} |
||||
} |
||||
|
||||
return errs |
||||
} |
||||
|
||||
// ValidationFunc accepts all values needed for file and cross field validation
|
||||
// top = top level struct when validating by struct otherwise nil
|
||||
// current = current level struct when validating by struct otherwise optional comparison value
|
||||
// f = field value for validation
|
||||
// param = parameter used in validation i.e. gt=0 param would be 0
|
||||
type ValidationFunc func(top interface{}, current interface{}, f interface{}, param string) bool |
||||
|
||||
// Validator implements the Validator Struct
|
||||
// NOTE: Fields within are not thread safe and that is on purpose
|
||||
// Functions and Tags should all be predifined before use, so subscribe to the philosiphy
|
||||
// or make it thread safe on your end
|
||||
type Validator struct { |
||||
// tagName being used.
|
||||
tagName string |
||||
// validationFuncs is a map of validation functions and the tag keys
|
||||
validationFuncs map[string]ValidationFunc |
||||
} |
||||
|
||||
// NewValidator creates a new Validator instance for use.
|
||||
func NewValidator(tagName string, funcs map[string]ValidationFunc) *Validator { |
||||
return &Validator{ |
||||
tagName: tagName, |
||||
validationFuncs: funcs, |
||||
v.traverseField(ctx, current, current.Field(f.idx), ns, structNs, f, f.cTags) |
||||
} |
||||
} |
||||
|
||||
// SetTag sets tagName of the Validator to one of your choosing after creation
|
||||
// perhaps to dodge a tag name conflict in a specific section of code
|
||||
func (v *Validator) SetTag(tagName string) { |
||||
v.tagName = tagName |
||||
} |
||||
// check if any struct level validations, after all field validations already checked.
|
||||
// first iteration will have no info about nostructlevel tag, and is checked prior to
|
||||
// calling the next iteration of validateStruct called from traverseField.
|
||||
if cs.fn != nil { |
||||
|
||||
// AddFunction adds a ValidationFunc to a Validator's map of validators denoted by the key
|
||||
// NOTE: if the key already exists, it will get replaced.
|
||||
func (v *Validator) AddFunction(key string, f ValidationFunc) error { |
||||
v.slflParent = parent |
||||
v.slCurrent = current |
||||
v.ns = ns |
||||
v.actualNs = structNs |
||||
|
||||
if len(key) == 0 { |
||||
return errors.New("Function Key cannot be empty") |
||||
cs.fn(ctx, v) |
||||
} |
||||
|
||||
if f == nil { |
||||
return errors.New("Function cannot be empty") |
||||
} |
||||
|
||||
v.validationFuncs[key] = f |
||||
// traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options
|
||||
func (v *validate) traverseField(ctx context.Context, parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) { |
||||
var typ reflect.Type |
||||
var kind reflect.Kind |
||||
|
||||
return nil |
||||
} |
||||
current, kind, v.fldIsPointer = v.extractTypeInternal(current, false) |
||||
|
||||
// ValidateStruct validates a struct, even it's nested structs, and returns a struct containing the errors
|
||||
// NOTE: Nested Arrays, or Maps of structs do not get validated only the Array or Map itself; the reason is that there is no good
|
||||
// way to represent or report which struct within the array has the error, besides can validate the struct prior to adding it to
|
||||
// the Array or Map.
|
||||
func (v *Validator) ValidateStruct(s interface{}) *StructValidationErrors { |
||||
switch kind { |
||||
case reflect.Ptr, reflect.Interface, reflect.Invalid: |
||||
|
||||
return v.validateStructRecursive(s, s, s) |
||||
if ct == nil { |
||||
return |
||||
} |
||||
|
||||
// validateStructRecursive validates a struct recursivly and passes the top level and current struct around for use in validator functions and returns a struct containing the errors
|
||||
func (v *Validator) validateStructRecursive(top interface{}, current interface{}, s interface{}) *StructValidationErrors { |
||||
|
||||
structValue := reflect.ValueOf(s) |
||||
structType := reflect.TypeOf(s) |
||||
structName := structType.Name() |
||||
|
||||
if structValue.Kind() == reflect.Ptr && !structValue.IsNil() { |
||||
return v.validateStructRecursive(top, current, structValue.Elem().Interface()) |
||||
if ct.typeof == typeOmitEmpty || ct.typeof == typeIsDefault { |
||||
return |
||||
} |
||||
|
||||
if structValue.Kind() != reflect.Struct && structValue.Kind() != reflect.Interface { |
||||
panic("interface passed for validation is not a struct") |
||||
if ct.hasTag { |
||||
if kind == reflect.Invalid { |
||||
v.str1 = string(append(ns, cf.altName...)) |
||||
if v.v.hasTagNameFunc { |
||||
v.str2 = string(append(structNs, cf.name...)) |
||||
} else { |
||||
v.str2 = v.str1 |
||||
} |
||||
v.errs = append(v.errs, |
||||
&fieldError{ |
||||
v: v.v, |
||||
tag: ct.aliasTag, |
||||
actualTag: ct.tag, |
||||
ns: v.str1, |
||||
structNs: v.str2, |
||||
fieldLen: uint8(len(cf.altName)), |
||||
structfieldLen: uint8(len(cf.name)), |
||||
param: ct.param, |
||||
kind: kind, |
||||
}, |
||||
) |
||||
return |
||||
} |
||||
|
||||
validationErrors := &StructValidationErrors{ |
||||
Struct: structName, |
||||
Errors: map[string]*FieldValidationError{}, |
||||
StructErrors: map[string]*StructValidationErrors{}, |
||||
v.str1 = string(append(ns, cf.altName...)) |
||||
if v.v.hasTagNameFunc { |
||||
v.str2 = string(append(structNs, cf.name...)) |
||||
} else { |
||||
v.str2 = v.str1 |
||||
} |
||||
if !ct.runValidationWhenNil { |
||||
v.errs = append(v.errs, |
||||
&fieldError{ |
||||
v: v.v, |
||||
tag: ct.aliasTag, |
||||
actualTag: ct.tag, |
||||
ns: v.str1, |
||||
structNs: v.str2, |
||||
fieldLen: uint8(len(cf.altName)), |
||||
structfieldLen: uint8(len(cf.name)), |
||||
value: current.Interface(), |
||||
param: ct.param, |
||||
kind: kind, |
||||
typ: current.Type(), |
||||
}, |
||||
) |
||||
return |
||||
} |
||||
} |
||||
|
||||
var numFields = structValue.NumField() |
||||
case reflect.Struct: |
||||
|
||||
for i := 0; i < numFields; i++ { |
||||
typ = current.Type() |
||||
|
||||
valueField := structValue.Field(i) |
||||
typeField := structType.Field(i) |
||||
if !typ.ConvertibleTo(timeType) { |
||||
|
||||
if valueField.Kind() == reflect.Ptr && !valueField.IsNil() { |
||||
valueField = valueField.Elem() |
||||
} |
||||
if ct != nil { |
||||
|
||||
tag := typeField.Tag.Get(v.tagName) |
||||
if ct.typeof == typeStructOnly { |
||||
goto CONTINUE |
||||
} else if ct.typeof == typeIsDefault { |
||||
// set Field Level fields
|
||||
v.slflParent = parent |
||||
v.flField = current |
||||
v.cf = cf |
||||
v.ct = ct |
||||
|
||||
if tag == noValidationTag { |
||||
continue |
||||
} |
||||
if !ct.fn(ctx, v) { |
||||
v.str1 = string(append(ns, cf.altName...)) |
||||
|
||||
// if no validation and not a struct (which may containt fields for validation)
|
||||
if tag == "" && valueField.Kind() != reflect.Struct && valueField.Kind() != reflect.Interface { |
||||
continue |
||||
if v.v.hasTagNameFunc { |
||||
v.str2 = string(append(structNs, cf.name...)) |
||||
} else { |
||||
v.str2 = v.str1 |
||||
} |
||||
|
||||
v.errs = append(v.errs, |
||||
&fieldError{ |
||||
v: v.v, |
||||
tag: ct.aliasTag, |
||||
actualTag: ct.tag, |
||||
ns: v.str1, |
||||
structNs: v.str2, |
||||
fieldLen: uint8(len(cf.altName)), |
||||
structfieldLen: uint8(len(cf.name)), |
||||
value: current.Interface(), |
||||
param: ct.param, |
||||
kind: kind, |
||||
typ: typ, |
||||
}, |
||||
) |
||||
return |
||||
} |
||||
|
||||
switch valueField.Kind() { |
||||
|
||||
case reflect.Struct, reflect.Interface: |
||||
|
||||
if !unicode.IsUpper(rune(typeField.Name[0])) { |
||||
continue |
||||
} |
||||
|
||||
if valueField.Type() == reflect.TypeOf(time.Time{}) { |
||||
|
||||
if fieldError := v.validateFieldByNameAndTagAndValue(top, current, valueField.Interface(), typeField.Name, tag); fieldError != nil { |
||||
validationErrors.Errors[fieldError.Field] = fieldError |
||||
// free up memory reference
|
||||
fieldError = nil |
||||
ct = ct.next |
||||
} |
||||
|
||||
} else { |
||||
|
||||
if strings.Contains(tag, structOnlyTag) { |
||||
continue |
||||
if ct != nil && ct.typeof == typeNoStructLevel { |
||||
return |
||||
} |
||||
|
||||
if structErrors := v.validateStructRecursive(top, valueField.Interface(), valueField.Interface()); structErrors != nil { |
||||
validationErrors.StructErrors[typeField.Name] = structErrors |
||||
// free up memory map no longer needed
|
||||
structErrors = nil |
||||
} |
||||
CONTINUE: |
||||
// if len == 0 then validating using 'Var' or 'VarWithValue'
|
||||
// Var - doesn't make much sense to do it that way, should call 'Struct', but no harm...
|
||||
// VarWithField - this allows for validating against each field within the struct against a specific value
|
||||
// pretty handy in certain situations
|
||||
if len(cf.name) > 0 { |
||||
ns = append(append(ns, cf.altName...), '.') |
||||
structNs = append(append(structNs, cf.name...), '.') |
||||
} |
||||
|
||||
default: |
||||
|
||||
if fieldError := v.validateFieldByNameAndTagAndValue(top, current, valueField.Interface(), typeField.Name, tag); fieldError != nil { |
||||
validationErrors.Errors[fieldError.Field] = fieldError |
||||
// free up memory reference
|
||||
fieldError = nil |
||||
} |
||||
v.validateStruct(ctx, parent, current, typ, ns, structNs, ct) |
||||
return |
||||
} |
||||
} |
||||
|
||||
if len(validationErrors.Errors) == 0 && len(validationErrors.StructErrors) == 0 { |
||||
return nil |
||||
if ct == nil || !ct.hasTag { |
||||
return |
||||
} |
||||
|
||||
return validationErrors |
||||
typ = current.Type() |
||||
|
||||
OUTER: |
||||
for { |
||||
if ct == nil { |
||||
return |
||||
} |
||||
|
||||
// ValidateFieldByTag allows validation of a single field, still using tag style validation to check multiple errors
|
||||
func (v *Validator) ValidateFieldByTag(f interface{}, tag string) *FieldValidationError { |
||||
switch ct.typeof { |
||||
|
||||
return v.ValidateFieldByTagAndValue(nil, f, tag) |
||||
} |
||||
case typeOmitEmpty: |
||||
|
||||
// ValidateFieldByTagAndValue allows validation of a single field, possibly even against another fields value, still using tag style validation to check multiple errors
|
||||
func (v *Validator) ValidateFieldByTagAndValue(val interface{}, f interface{}, tag string) *FieldValidationError { |
||||
// set Field Level fields
|
||||
v.slflParent = parent |
||||
v.flField = current |
||||
v.cf = cf |
||||
v.ct = ct |
||||
|
||||
return v.validateFieldByNameAndTagAndValue(nil, val, f, "", tag) |
||||
if !hasValue(v) { |
||||
return |
||||
} |
||||
|
||||
func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, current interface{}, f interface{}, name string, tag string) *FieldValidationError { |
||||
ct = ct.next |
||||
continue |
||||
|
||||
// This is a double check if coming from ValidateStruct but need to be here in case function is called directly
|
||||
if tag == noValidationTag { |
||||
return nil |
||||
} |
||||
case typeEndKeys: |
||||
return |
||||
|
||||
if strings.Contains(tag, omitempty) && !hasValue(val, current, f, "") { |
||||
return nil |
||||
} |
||||
case typeDive: |
||||
|
||||
valueField := reflect.ValueOf(f) |
||||
fieldKind := valueField.Kind() |
||||
ct = ct.next |
||||
|
||||
if fieldKind == reflect.Ptr && !valueField.IsNil() { |
||||
return v.validateFieldByNameAndTagAndValue(val, current, valueField.Elem().Interface(), name, tag) |
||||
} |
||||
// traverse slice or map here
|
||||
// or panic ;)
|
||||
switch kind { |
||||
case reflect.Slice, reflect.Array: |
||||
|
||||
var i64 int64 |
||||
reusableCF := &cField{} |
||||
|
||||
for i := 0; i < current.Len(); i++ { |
||||
|
||||
fieldType := valueField.Type() |
||||
i64 = int64(i) |
||||
|
||||
switch fieldKind { |
||||
v.misc = append(v.misc[0:0], cf.name...) |
||||
v.misc = append(v.misc, '[') |
||||
v.misc = strconv.AppendInt(v.misc, i64, 10) |
||||
v.misc = append(v.misc, ']') |
||||
|
||||
case reflect.Struct, reflect.Interface, reflect.Invalid: |
||||
reusableCF.name = string(v.misc) |
||||
|
||||
if fieldType != reflect.TypeOf(time.Time{}) { |
||||
panic("Invalid field passed to ValidateFieldWithTag") |
||||
if cf.namesEqual { |
||||
reusableCF.altName = reusableCF.name |
||||
} else { |
||||
|
||||
v.misc = append(v.misc[0:0], cf.altName...) |
||||
v.misc = append(v.misc, '[') |
||||
v.misc = strconv.AppendInt(v.misc, i64, 10) |
||||
v.misc = append(v.misc, ']') |
||||
|
||||
reusableCF.altName = string(v.misc) |
||||
} |
||||
v.traverseField(ctx, parent, current.Index(i), ns, structNs, reusableCF, ct) |
||||
} |
||||
|
||||
var valErr *FieldValidationError |
||||
var err error |
||||
valTags := strings.Split(tag, tagSeparator) |
||||
case reflect.Map: |
||||
|
||||
for _, valTag := range valTags { |
||||
var pv string |
||||
reusableCF := &cField{} |
||||
|
||||
orVals := strings.Split(valTag, orSeparator) |
||||
for _, key := range current.MapKeys() { |
||||
|
||||
if len(orVals) > 1 { |
||||
pv = fmt.Sprintf("%v", key.Interface()) |
||||
|
||||
errTag := "" |
||||
v.misc = append(v.misc[0:0], cf.name...) |
||||
v.misc = append(v.misc, '[') |
||||
v.misc = append(v.misc, pv...) |
||||
v.misc = append(v.misc, ']') |
||||
|
||||
for _, val := range orVals { |
||||
reusableCF.name = string(v.misc) |
||||
|
||||
valErr, err = v.validateFieldByNameAndSingleTag(val, current, f, name, val) |
||||
if cf.namesEqual { |
||||
reusableCF.altName = reusableCF.name |
||||
} else { |
||||
v.misc = append(v.misc[0:0], cf.altName...) |
||||
v.misc = append(v.misc, '[') |
||||
v.misc = append(v.misc, pv...) |
||||
v.misc = append(v.misc, ']') |
||||
|
||||
if err == nil { |
||||
return nil |
||||
reusableCF.altName = string(v.misc) |
||||
} |
||||
|
||||
errTag += orSeparator + valErr.ErrorTag |
||||
if ct != nil && ct.typeof == typeKeys && ct.keys != nil { |
||||
v.traverseField(ctx, parent, key, ns, structNs, reusableCF, ct.keys) |
||||
// can be nil when just keys being validated
|
||||
if ct.next != nil { |
||||
v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct.next) |
||||
} |
||||
} else { |
||||
v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct) |
||||
} |
||||
} |
||||
|
||||
default: |
||||
// throw error, if not a slice or map then should not have gotten here
|
||||
// bad dive tag
|
||||
panic("dive error! can't dive on a non slice or map") |
||||
} |
||||
|
||||
errTag = strings.TrimLeft(errTag, orSeparator) |
||||
return |
||||
|
||||
valErr.ErrorTag = errTag |
||||
valErr.Kind = fieldKind |
||||
case typeOr: |
||||
|
||||
return valErr |
||||
} |
||||
v.misc = v.misc[0:0] |
||||
|
||||
if valErr, err = v.validateFieldByNameAndSingleTag(val, current, f, name, valTag); err != nil { |
||||
for { |
||||
|
||||
valErr.Kind = valueField.Kind() |
||||
valErr.Type = fieldType |
||||
// set Field Level fields
|
||||
v.slflParent = parent |
||||
v.flField = current |
||||
v.cf = cf |
||||
v.ct = ct |
||||
|
||||
return valErr |
||||
if ct.fn(ctx, v) { |
||||
if ct.isBlockEnd { |
||||
ct = ct.next |
||||
continue OUTER |
||||
} |
||||
|
||||
// drain rest of the 'or' values, then continue or leave
|
||||
for { |
||||
|
||||
ct = ct.next |
||||
|
||||
if ct == nil { |
||||
return |
||||
} |
||||
|
||||
return nil |
||||
if ct.typeof != typeOr { |
||||
continue OUTER |
||||
} |
||||
|
||||
func (v *Validator) validateFieldByNameAndSingleTag(val interface{}, current interface{}, f interface{}, name string, valTag string) (*FieldValidationError, error) { |
||||
if ct.isBlockEnd { |
||||
ct = ct.next |
||||
continue OUTER |
||||
} |
||||
} |
||||
} |
||||
|
||||
vals := strings.Split(valTag, tagKeySeparator) |
||||
key := strings.Trim(vals[0], " ") |
||||
v.misc = append(v.misc, '|') |
||||
v.misc = append(v.misc, ct.tag...) |
||||
|
||||
if len(key) == 0 { |
||||
panic(fmt.Sprintf("Invalid validation tag on field %s", name)) |
||||
if ct.hasParam { |
||||
v.misc = append(v.misc, '=') |
||||
v.misc = append(v.misc, ct.param...) |
||||
} |
||||
|
||||
valErr := &FieldValidationError{ |
||||
Field: name, |
||||
ErrorTag: key, |
||||
Value: f, |
||||
Param: "", |
||||
} |
||||
if ct.isBlockEnd || ct.next == nil { |
||||
// if we get here, no valid 'or' value and no more tags
|
||||
v.str1 = string(append(ns, cf.altName...)) |
||||
|
||||
if v.v.hasTagNameFunc { |
||||
v.str2 = string(append(structNs, cf.name...)) |
||||
} else { |
||||
v.str2 = v.str1 |
||||
} |
||||
|
||||
if ct.hasAlias { |
||||
|
||||
v.errs = append(v.errs, |
||||
&fieldError{ |
||||
v: v.v, |
||||
tag: ct.aliasTag, |
||||
actualTag: ct.actualAliasTag, |
||||
ns: v.str1, |
||||
structNs: v.str2, |
||||
fieldLen: uint8(len(cf.altName)), |
||||
structfieldLen: uint8(len(cf.name)), |
||||
value: current.Interface(), |
||||
param: ct.param, |
||||
kind: kind, |
||||
typ: typ, |
||||
}, |
||||
) |
||||
|
||||
} else { |
||||
|
||||
// OK to continue because we checked it's existance before getting into this loop
|
||||
if key == omitempty { |
||||
return valErr, nil |
||||
tVal := string(v.misc)[1:] |
||||
|
||||
v.errs = append(v.errs, |
||||
&fieldError{ |
||||
v: v.v, |
||||
tag: tVal, |
||||
actualTag: tVal, |
||||
ns: v.str1, |
||||
structNs: v.str2, |
||||
fieldLen: uint8(len(cf.altName)), |
||||
structfieldLen: uint8(len(cf.name)), |
||||
value: current.Interface(), |
||||
param: ct.param, |
||||
kind: kind, |
||||
typ: typ, |
||||
}, |
||||
) |
||||
} |
||||
|
||||
valFunc, ok := v.validationFuncs[key] |
||||
if !ok { |
||||
panic(fmt.Sprintf("Undefined validation function on field %s", name)) |
||||
return |
||||
} |
||||
|
||||
param := "" |
||||
if len(vals) > 1 { |
||||
param = strings.Trim(vals[1], " ") |
||||
ct = ct.next |
||||
} |
||||
|
||||
if err := valFunc(val, current, f, param); !err { |
||||
valErr.Param = param |
||||
return valErr, errors.New(key) |
||||
default: |
||||
|
||||
// set Field Level fields
|
||||
v.slflParent = parent |
||||
v.flField = current |
||||
v.cf = cf |
||||
v.ct = ct |
||||
|
||||
if !ct.fn(ctx, v) { |
||||
v.str1 = string(append(ns, cf.altName...)) |
||||
|
||||
if v.v.hasTagNameFunc { |
||||
v.str2 = string(append(structNs, cf.name...)) |
||||
} else { |
||||
v.str2 = v.str1 |
||||
} |
||||
|
||||
v.errs = append(v.errs, |
||||
&fieldError{ |
||||
v: v.v, |
||||
tag: ct.aliasTag, |
||||
actualTag: ct.tag, |
||||
ns: v.str1, |
||||
structNs: v.str2, |
||||
fieldLen: uint8(len(cf.altName)), |
||||
structfieldLen: uint8(len(cf.name)), |
||||
value: current.Interface(), |
||||
param: ct.param, |
||||
kind: kind, |
||||
typ: typ, |
||||
}, |
||||
) |
||||
|
||||
return |
||||
} |
||||
ct = ct.next |
||||
} |
||||
} |
||||
|
||||
return valErr, nil |
||||
} |
||||
|
@ -0,0 +1,700 @@ |
||||
package validator |
||||
|
||||
import ( |
||||
"context" |
||||
"errors" |
||||
"fmt" |
||||
"reflect" |
||||
"strings" |
||||
"sync" |
||||
"time" |
||||
|
||||
ut "github.com/go-playground/universal-translator" |
||||
) |
||||
|
||||
const ( |
||||
defaultTagName = "validate" |
||||
utf8HexComma = "0x2C" |
||||
utf8Pipe = "0x7C" |
||||
tagSeparator = "," |
||||
orSeparator = "|" |
||||
tagKeySeparator = "=" |
||||
structOnlyTag = "structonly" |
||||
noStructLevelTag = "nostructlevel" |
||||
omitempty = "omitempty" |
||||
isdefault = "isdefault" |
||||
requiredWithoutAllTag = "required_without_all" |
||||
requiredWithoutTag = "required_without" |
||||
requiredWithTag = "required_with" |
||||
requiredWithAllTag = "required_with_all" |
||||
requiredIfTag = "required_if" |
||||
requiredUnlessTag = "required_unless" |
||||
excludedWithoutAllTag = "excluded_without_all" |
||||
excludedWithoutTag = "excluded_without" |
||||
excludedWithTag = "excluded_with" |
||||
excludedWithAllTag = "excluded_with_all" |
||||
excludedIfTag = "excluded_if" |
||||
excludedUnlessTag = "excluded_unless" |
||||
skipValidationTag = "-" |
||||
diveTag = "dive" |
||||
keysTag = "keys" |
||||
endKeysTag = "endkeys" |
||||
requiredTag = "required" |
||||
namespaceSeparator = "." |
||||
leftBracket = "[" |
||||
rightBracket = "]" |
||||
restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}" |
||||
restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" |
||||
restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" |
||||
) |
||||
|
||||
var ( |
||||
timeDurationType = reflect.TypeOf(time.Duration(0)) |
||||
timeType = reflect.TypeOf(time.Time{}) |
||||
|
||||
defaultCField = &cField{namesEqual: true} |
||||
) |
||||
|
||||
// FilterFunc is the type used to filter fields using
|
||||
// StructFiltered(...) function.
|
||||
// returning true results in the field being filtered/skiped from
|
||||
// validation
|
||||
type FilterFunc func(ns []byte) bool |
||||
|
||||
// CustomTypeFunc allows for overriding or adding custom field type handler functions
|
||||
// field = field value of the type to return a value to be validated
|
||||
// example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29
|
||||
type CustomTypeFunc func(field reflect.Value) interface{} |
||||
|
||||
// TagNameFunc allows for adding of a custom tag name parser
|
||||
type TagNameFunc func(field reflect.StructField) string |
||||
|
||||
type internalValidationFuncWrapper struct { |
||||
fn FuncCtx |
||||
runValidatinOnNil bool |
||||
} |
||||
|
||||
// Validate contains the validator settings and cache
|
||||
type Validate struct { |
||||
tagName string |
||||
pool *sync.Pool |
||||
hasCustomFuncs bool |
||||
hasTagNameFunc bool |
||||
tagNameFunc TagNameFunc |
||||
structLevelFuncs map[reflect.Type]StructLevelFuncCtx |
||||
customFuncs map[reflect.Type]CustomTypeFunc |
||||
aliases map[string]string |
||||
validations map[string]internalValidationFuncWrapper |
||||
transTagFunc map[ut.Translator]map[string]TranslationFunc // map[<locale>]map[<tag>]TranslationFunc
|
||||
rules map[reflect.Type]map[string]string |
||||
tagCache *tagCache |
||||
structCache *structCache |
||||
} |
||||
|
||||
// New returns a new instance of 'validate' with sane defaults.
|
||||
// Validate is designed to be thread-safe and used as a singleton instance.
|
||||
// It caches information about your struct and validations,
|
||||
// in essence only parsing your validation tags once per struct type.
|
||||
// Using multiple instances neglects the benefit of caching.
|
||||
func New() *Validate { |
||||
|
||||
tc := new(tagCache) |
||||
tc.m.Store(make(map[string]*cTag)) |
||||
|
||||
sc := new(structCache) |
||||
sc.m.Store(make(map[reflect.Type]*cStruct)) |
||||
|
||||
v := &Validate{ |
||||
tagName: defaultTagName, |
||||
aliases: make(map[string]string, len(bakedInAliases)), |
||||
validations: make(map[string]internalValidationFuncWrapper, len(bakedInValidators)), |
||||
tagCache: tc, |
||||
structCache: sc, |
||||
} |
||||
|
||||
// must copy alias validators for separate validations to be used in each validator instance
|
||||
for k, val := range bakedInAliases { |
||||
v.RegisterAlias(k, val) |
||||
} |
||||
|
||||
// must copy validators for separate validations to be used in each instance
|
||||
for k, val := range bakedInValidators { |
||||
|
||||
switch k { |
||||
// these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour
|
||||
case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag, |
||||
excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag: |
||||
_ = v.registerValidation(k, wrapFunc(val), true, true) |
||||
default: |
||||
// no need to error check here, baked in will always be valid
|
||||
_ = v.registerValidation(k, wrapFunc(val), true, false) |
||||
} |
||||
} |
||||
|
||||
v.pool = &sync.Pool{ |
||||
New: func() interface{} { |
||||
return &validate{ |
||||
v: v, |
||||
ns: make([]byte, 0, 64), |
||||
actualNs: make([]byte, 0, 64), |
||||
misc: make([]byte, 32), |
||||
} |
||||
}, |
||||
} |
||||
|
||||
return v |
||||
} |
||||
|
||||
// SetTagName allows for changing of the default tag name of 'validate'
|
||||
func (v *Validate) SetTagName(name string) { |
||||
v.tagName = name |
||||
} |
||||
|
||||
// ValidateMapCtx validates a map using a map of validation rules and allows passing of contextual
|
||||
// validation validation information via context.Context.
|
||||
func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} { |
||||
errs := make(map[string]interface{}) |
||||
for field, rule := range rules { |
||||
if ruleObj, ok := rule.(map[string]interface{}); ok { |
||||
if dataObj, ok := data[field].(map[string]interface{}); ok { |
||||
err := v.ValidateMapCtx(ctx, dataObj, ruleObj) |
||||
if len(err) > 0 { |
||||
errs[field] = err |
||||
} |
||||
} else if dataObjs, ok := data[field].([]map[string]interface{}); ok { |
||||
for _, obj := range dataObjs { |
||||
err := v.ValidateMapCtx(ctx, obj, ruleObj) |
||||
if len(err) > 0 { |
||||
errs[field] = err |
||||
} |
||||
} |
||||
} else { |
||||
errs[field] = errors.New("The field: '" + field + "' is not a map to dive") |
||||
} |
||||
} else if ruleStr, ok := rule.(string); ok { |
||||
err := v.VarCtx(ctx, data[field], ruleStr) |
||||
if err != nil { |
||||
errs[field] = err |
||||
} |
||||
} |
||||
} |
||||
return errs |
||||
} |
||||
|
||||
// ValidateMap validates map data from a map of tags
|
||||
func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{} { |
||||
return v.ValidateMapCtx(context.Background(), data, rules) |
||||
} |
||||
|
||||
// RegisterTagNameFunc registers a function to get alternate names for StructFields.
|
||||
//
|
||||
// eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names:
|
||||
//
|
||||
// validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
|
||||
// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
|
||||
// // skip if tag key says it should be ignored
|
||||
// if name == "-" {
|
||||
// return ""
|
||||
// }
|
||||
// return name
|
||||
// })
|
||||
func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) { |
||||
v.tagNameFunc = fn |
||||
v.hasTagNameFunc = true |
||||
} |
||||
|
||||
// RegisterValidation adds a validation with the given tag
|
||||
//
|
||||
// NOTES:
|
||||
// - if the key already exists, the previous validation function will be replaced.
|
||||
// - this method is not thread-safe it is intended that these all be registered prior to any validation
|
||||
func (v *Validate) RegisterValidation(tag string, fn Func, callValidationEvenIfNull ...bool) error { |
||||
return v.RegisterValidationCtx(tag, wrapFunc(fn), callValidationEvenIfNull...) |
||||
} |
||||
|
||||
// RegisterValidationCtx does the same as RegisterValidation on accepts a FuncCtx validation
|
||||
// allowing context.Context validation support.
|
||||
func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationEvenIfNull ...bool) error { |
||||
var nilCheckable bool |
||||
if len(callValidationEvenIfNull) > 0 { |
||||
nilCheckable = callValidationEvenIfNull[0] |
||||
} |
||||
return v.registerValidation(tag, fn, false, nilCheckable) |
||||
} |
||||
|
||||
func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error { |
||||
if len(tag) == 0 { |
||||
return errors.New("function Key cannot be empty") |
||||
} |
||||
|
||||
if fn == nil { |
||||
return errors.New("function cannot be empty") |
||||
} |
||||
|
||||
_, ok := restrictedTags[tag] |
||||
if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) { |
||||
panic(fmt.Sprintf(restrictedTagErr, tag)) |
||||
} |
||||
v.validations[tag] = internalValidationFuncWrapper{fn: fn, runValidatinOnNil: nilCheckable} |
||||
return nil |
||||
} |
||||
|
||||
// RegisterAlias registers a mapping of a single validation tag that
|
||||
// defines a common or complex set of validation(s) to simplify adding validation
|
||||
// to structs.
|
||||
//
|
||||
// NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation
|
||||
func (v *Validate) RegisterAlias(alias, tags string) { |
||||
|
||||
_, ok := restrictedTags[alias] |
||||
|
||||
if ok || strings.ContainsAny(alias, restrictedTagChars) { |
||||
panic(fmt.Sprintf(restrictedAliasErr, alias)) |
||||
} |
||||
|
||||
v.aliases[alias] = tags |
||||
} |
||||
|
||||
// RegisterStructValidation registers a StructLevelFunc against a number of types.
|
||||
//
|
||||
// NOTE:
|
||||
// - this method is not thread-safe it is intended that these all be registered prior to any validation
|
||||
func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) { |
||||
v.RegisterStructValidationCtx(wrapStructLevelFunc(fn), types...) |
||||
} |
||||
|
||||
// RegisterStructValidationCtx registers a StructLevelFuncCtx against a number of types and allows passing
|
||||
// of contextual validation information via context.Context.
|
||||
//
|
||||
// NOTE:
|
||||
// - this method is not thread-safe it is intended that these all be registered prior to any validation
|
||||
func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...interface{}) { |
||||
|
||||
if v.structLevelFuncs == nil { |
||||
v.structLevelFuncs = make(map[reflect.Type]StructLevelFuncCtx) |
||||
} |
||||
|
||||
for _, t := range types { |
||||
tv := reflect.ValueOf(t) |
||||
if tv.Kind() == reflect.Ptr { |
||||
t = reflect.Indirect(tv).Interface() |
||||
} |
||||
|
||||
v.structLevelFuncs[reflect.TypeOf(t)] = fn |
||||
} |
||||
} |
||||
|
||||
// RegisterStructValidationMapRules registers validate map rules.
|
||||
// Be aware that map validation rules supersede those defined on a/the struct if present.
|
||||
//
|
||||
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
|
||||
func (v *Validate) RegisterStructValidationMapRules(rules map[string]string, types ...interface{}) { |
||||
if v.rules == nil { |
||||
v.rules = make(map[reflect.Type]map[string]string) |
||||
} |
||||
|
||||
deepCopyRules := make(map[string]string) |
||||
for i, rule := range rules { |
||||
deepCopyRules[i] = rule |
||||
} |
||||
|
||||
for _, t := range types { |
||||
typ := reflect.TypeOf(t) |
||||
|
||||
if typ.Kind() == reflect.Ptr { |
||||
typ = typ.Elem() |
||||
} |
||||
|
||||
if typ.Kind() != reflect.Struct { |
||||
continue |
||||
} |
||||
v.rules[typ] = deepCopyRules |
||||
} |
||||
} |
||||
|
||||
// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
|
||||
//
|
||||
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
|
||||
func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) { |
||||
|
||||
if v.customFuncs == nil { |
||||
v.customFuncs = make(map[reflect.Type]CustomTypeFunc) |
||||
} |
||||
|
||||
for _, t := range types { |
||||
v.customFuncs[reflect.TypeOf(t)] = fn |
||||
} |
||||
|
||||
v.hasCustomFuncs = true |
||||
} |
||||
|
||||
// RegisterTranslation registers translations against the provided tag.
|
||||
func (v *Validate) RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) (err error) { |
||||
|
||||
if v.transTagFunc == nil { |
||||
v.transTagFunc = make(map[ut.Translator]map[string]TranslationFunc) |
||||
} |
||||
|
||||
if err = registerFn(trans); err != nil { |
||||
return |
||||
} |
||||
|
||||
m, ok := v.transTagFunc[trans] |
||||
if !ok { |
||||
m = make(map[string]TranslationFunc) |
||||
v.transTagFunc[trans] = m |
||||
} |
||||
|
||||
m[tag] = translationFn |
||||
|
||||
return |
||||
} |
||||
|
||||
// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified.
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
func (v *Validate) Struct(s interface{}) error { |
||||
return v.StructCtx(context.Background(), s) |
||||
} |
||||
|
||||
// StructCtx validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified
|
||||
// and also allows passing of context.Context for contextual validation information.
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) { |
||||
|
||||
val := reflect.ValueOf(s) |
||||
top := val |
||||
|
||||
if val.Kind() == reflect.Ptr && !val.IsNil() { |
||||
val = val.Elem() |
||||
} |
||||
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { |
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)} |
||||
} |
||||
|
||||
// good to validate
|
||||
vd := v.pool.Get().(*validate) |
||||
vd.top = top |
||||
vd.isPartial = false |
||||
// vd.hasExcludes = false // only need to reset in StructPartial and StructExcept
|
||||
|
||||
vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) |
||||
|
||||
if len(vd.errs) > 0 { |
||||
err = vd.errs |
||||
vd.errs = nil |
||||
} |
||||
|
||||
v.pool.Put(vd) |
||||
|
||||
return |
||||
} |
||||
|
||||
// StructFiltered validates a structs exposed fields, that pass the FilterFunc check and automatically validates
|
||||
// nested structs, unless otherwise specified.
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) error { |
||||
return v.StructFilteredCtx(context.Background(), s, fn) |
||||
} |
||||
|
||||
// StructFilteredCtx validates a structs exposed fields, that pass the FilterFunc check and automatically validates
|
||||
// nested structs, unless otherwise specified and also allows passing of contextual validation information via
|
||||
// context.Context
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn FilterFunc) (err error) { |
||||
val := reflect.ValueOf(s) |
||||
top := val |
||||
|
||||
if val.Kind() == reflect.Ptr && !val.IsNil() { |
||||
val = val.Elem() |
||||
} |
||||
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { |
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)} |
||||
} |
||||
|
||||
// good to validate
|
||||
vd := v.pool.Get().(*validate) |
||||
vd.top = top |
||||
vd.isPartial = true |
||||
vd.ffn = fn |
||||
// vd.hasExcludes = false // only need to reset in StructPartial and StructExcept
|
||||
|
||||
vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) |
||||
|
||||
if len(vd.errs) > 0 { |
||||
err = vd.errs |
||||
vd.errs = nil |
||||
} |
||||
|
||||
v.pool.Put(vd) |
||||
|
||||
return |
||||
} |
||||
|
||||
// StructPartial validates the fields passed in only, ignoring all others.
|
||||
// Fields may be provided in a namespaced fashion relative to the struct provided
|
||||
// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
func (v *Validate) StructPartial(s interface{}, fields ...string) error { |
||||
return v.StructPartialCtx(context.Background(), s, fields...) |
||||
} |
||||
|
||||
// StructPartialCtx validates the fields passed in only, ignoring all others and allows passing of contextual
|
||||
// validation validation information via context.Context
|
||||
// Fields may be provided in a namespaced fashion relative to the struct provided
|
||||
// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields ...string) (err error) { |
||||
val := reflect.ValueOf(s) |
||||
top := val |
||||
|
||||
if val.Kind() == reflect.Ptr && !val.IsNil() { |
||||
val = val.Elem() |
||||
} |
||||
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { |
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)} |
||||
} |
||||
|
||||
// good to validate
|
||||
vd := v.pool.Get().(*validate) |
||||
vd.top = top |
||||
vd.isPartial = true |
||||
vd.ffn = nil |
||||
vd.hasExcludes = false |
||||
vd.includeExclude = make(map[string]struct{}) |
||||
|
||||
typ := val.Type() |
||||
name := typ.Name() |
||||
|
||||
for _, k := range fields { |
||||
|
||||
flds := strings.Split(k, namespaceSeparator) |
||||
if len(flds) > 0 { |
||||
|
||||
vd.misc = append(vd.misc[0:0], name...) |
||||
// Don't append empty name for unnamed structs
|
||||
if len(vd.misc) != 0 { |
||||
vd.misc = append(vd.misc, '.') |
||||
} |
||||
|
||||
for _, s := range flds { |
||||
|
||||
idx := strings.Index(s, leftBracket) |
||||
|
||||
if idx != -1 { |
||||
for idx != -1 { |
||||
vd.misc = append(vd.misc, s[:idx]...) |
||||
vd.includeExclude[string(vd.misc)] = struct{}{} |
||||
|
||||
idx2 := strings.Index(s, rightBracket) |
||||
idx2++ |
||||
vd.misc = append(vd.misc, s[idx:idx2]...) |
||||
vd.includeExclude[string(vd.misc)] = struct{}{} |
||||
s = s[idx2:] |
||||
idx = strings.Index(s, leftBracket) |
||||
} |
||||
} else { |
||||
|
||||
vd.misc = append(vd.misc, s...) |
||||
vd.includeExclude[string(vd.misc)] = struct{}{} |
||||
} |
||||
|
||||
vd.misc = append(vd.misc, '.') |
||||
} |
||||
} |
||||
} |
||||
|
||||
vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) |
||||
|
||||
if len(vd.errs) > 0 { |
||||
err = vd.errs |
||||
vd.errs = nil |
||||
} |
||||
|
||||
v.pool.Put(vd) |
||||
|
||||
return |
||||
} |
||||
|
||||
// StructExcept validates all fields except the ones passed in.
|
||||
// Fields may be provided in a namespaced fashion relative to the struct provided
|
||||
// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
func (v *Validate) StructExcept(s interface{}, fields ...string) error { |
||||
return v.StructExceptCtx(context.Background(), s, fields...) |
||||
} |
||||
|
||||
// StructExceptCtx validates all fields except the ones passed in and allows passing of contextual
|
||||
// validation validation information via context.Context
|
||||
// Fields may be provided in a namespaced fashion relative to the struct provided
|
||||
// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ...string) (err error) { |
||||
val := reflect.ValueOf(s) |
||||
top := val |
||||
|
||||
if val.Kind() == reflect.Ptr && !val.IsNil() { |
||||
val = val.Elem() |
||||
} |
||||
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { |
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)} |
||||
} |
||||
|
||||
// good to validate
|
||||
vd := v.pool.Get().(*validate) |
||||
vd.top = top |
||||
vd.isPartial = true |
||||
vd.ffn = nil |
||||
vd.hasExcludes = true |
||||
vd.includeExclude = make(map[string]struct{}) |
||||
|
||||
typ := val.Type() |
||||
name := typ.Name() |
||||
|
||||
for _, key := range fields { |
||||
|
||||
vd.misc = vd.misc[0:0] |
||||
|
||||
if len(name) > 0 { |
||||
vd.misc = append(vd.misc, name...) |
||||
vd.misc = append(vd.misc, '.') |
||||
} |
||||
|
||||
vd.misc = append(vd.misc, key...) |
||||
vd.includeExclude[string(vd.misc)] = struct{}{} |
||||
} |
||||
|
||||
vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) |
||||
|
||||
if len(vd.errs) > 0 { |
||||
err = vd.errs |
||||
vd.errs = nil |
||||
} |
||||
|
||||
v.pool.Put(vd) |
||||
|
||||
return |
||||
} |
||||
|
||||
// Var validates a single variable using tag style validation.
|
||||
// eg.
|
||||
// var i int
|
||||
// validate.Var(i, "gt=1,lt=10")
|
||||
//
|
||||
// WARNING: a struct can be passed for validation eg. time.Time is a struct or
|
||||
// if you have a custom type and have registered a custom type handler, so must
|
||||
// allow it; however unforeseen validations will occur if trying to validate a
|
||||
// struct that is meant to be passed to 'validate.Struct'
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
// validate Array, Slice and maps fields which may contain more than one error
|
||||
func (v *Validate) Var(field interface{}, tag string) error { |
||||
return v.VarCtx(context.Background(), field, tag) |
||||
} |
||||
|
||||
// VarCtx validates a single variable using tag style validation and allows passing of contextual
|
||||
// validation information via context.Context.
|
||||
// eg.
|
||||
// var i int
|
||||
// validate.Var(i, "gt=1,lt=10")
|
||||
//
|
||||
// WARNING: a struct can be passed for validation eg. time.Time is a struct or
|
||||
// if you have a custom type and have registered a custom type handler, so must
|
||||
// allow it; however unforeseen validations will occur if trying to validate a
|
||||
// struct that is meant to be passed to 'validate.Struct'
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
// validate Array, Slice and maps fields which may contain more than one error
|
||||
func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (err error) { |
||||
if len(tag) == 0 || tag == skipValidationTag { |
||||
return nil |
||||
} |
||||
|
||||
ctag := v.fetchCacheTag(tag) |
||||
|
||||
val := reflect.ValueOf(field) |
||||
vd := v.pool.Get().(*validate) |
||||
vd.top = val |
||||
vd.isPartial = false |
||||
vd.traverseField(ctx, val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) |
||||
|
||||
if len(vd.errs) > 0 { |
||||
err = vd.errs |
||||
vd.errs = nil |
||||
} |
||||
v.pool.Put(vd) |
||||
return |
||||
} |
||||
|
||||
// VarWithValue validates a single variable, against another variable/field's value using tag style validation
|
||||
// eg.
|
||||
// s1 := "abcd"
|
||||
// s2 := "abcd"
|
||||
// validate.VarWithValue(s1, s2, "eqcsfield") // returns true
|
||||
//
|
||||
// WARNING: a struct can be passed for validation eg. time.Time is a struct or
|
||||
// if you have a custom type and have registered a custom type handler, so must
|
||||
// allow it; however unforeseen validations will occur if trying to validate a
|
||||
// struct that is meant to be passed to 'validate.Struct'
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
// validate Array, Slice and maps fields which may contain more than one error
|
||||
func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) error { |
||||
return v.VarWithValueCtx(context.Background(), field, other, tag) |
||||
} |
||||
|
||||
// VarWithValueCtx validates a single variable, against another variable/field's value using tag style validation and
|
||||
// allows passing of contextual validation validation information via context.Context.
|
||||
// eg.
|
||||
// s1 := "abcd"
|
||||
// s2 := "abcd"
|
||||
// validate.VarWithValue(s1, s2, "eqcsfield") // returns true
|
||||
//
|
||||
// WARNING: a struct can be passed for validation eg. time.Time is a struct or
|
||||
// if you have a custom type and have registered a custom type handler, so must
|
||||
// allow it; however unforeseen validations will occur if trying to validate a
|
||||
// struct that is meant to be passed to 'validate.Struct'
|
||||
//
|
||||
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
|
||||
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
|
||||
// validate Array, Slice and maps fields which may contain more than one error
|
||||
func (v *Validate) VarWithValueCtx(ctx context.Context, field interface{}, other interface{}, tag string) (err error) { |
||||
if len(tag) == 0 || tag == skipValidationTag { |
||||
return nil |
||||
} |
||||
ctag := v.fetchCacheTag(tag) |
||||
otherVal := reflect.ValueOf(other) |
||||
vd := v.pool.Get().(*validate) |
||||
vd.top = otherVal |
||||
vd.isPartial = false |
||||
vd.traverseField(ctx, otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) |
||||
|
||||
if len(vd.errs) > 0 { |
||||
err = vd.errs |
||||
vd.errs = nil |
||||
} |
||||
v.pool.Put(vd) |
||||
return |
||||
} |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue