3
3
import static org .junit .jupiter .api .Assertions .assertFalse ;
4
4
import static org .junit .jupiter .api .Assertions .assertTrue ;
5
5
6
+ import java .io .File ;
7
+ import java .io .FileNotFoundException ;
8
+ import java .io .IOException ;
9
+ import java .io .PrintStream ;
6
10
import java .lang .reflect .Field ;
7
- import java .util .HashMap ;
8
- import java .util .HashSet ;
9
- import java .util .Locale ;
10
- import java .util .Map ;
11
- import java .util .ResourceBundle ;
12
- import java .util .Set ;
11
+ import java .util .*;
13
12
14
13
import javax .annotation .Nonnull ;
15
14
16
15
import org .junit .jupiter .api .Test ;
17
16
18
17
public class I18nCoverageTest {
19
18
20
-
21
-
22
19
final Set <Locale > locales = Set .of (
23
20
Locale .ENGLISH ,
24
21
Locale .GERMAN ,
@@ -28,7 +25,128 @@ public class I18nCoverageTest {
28
25
);
29
26
30
27
@ Test
31
- public void testCoverage () throws IllegalAccessException {
28
+ public void testPhraseCoverage () throws IOException {
29
+
30
+ Properties englishMessages = new Properties ();
31
+ englishMessages .load (I18nTestClass .class .getClassLoader ().getResourceAsStream ("Messages.properties" ));
32
+ I18nTestClass englishTestClass = getI18nTestClass (Locale .ENGLISH );
33
+ Set <String > englishPluralSuffixes = englishTestClass .getPluralSuffixes ();
34
+
35
+ Set <String > englishPluralKeys = new HashSet <>();
36
+ Set <String > englishKeys = new HashSet <>();
37
+ for (Object objectKey : englishMessages .keySet ()) {
38
+ String key = (String ) objectKey ;
39
+ if (isPluralKey (key , englishPluralSuffixes )) {
40
+ final String pluralKeyRoot = getPluralKeyRoot (key , englishPluralSuffixes );
41
+ englishPluralKeys .add (pluralKeyRoot );
42
+ } else {
43
+ englishKeys .add (key );
44
+ }
45
+ }
46
+
47
+ HashMap <Locale , Integer > foundKeys = new HashMap <>();
48
+ HashMap <Locale , Integer > foundPluralKeys = new HashMap <>();
49
+
50
+ for (Locale locale : locales ) {
51
+ if (!locale .equals (Locale .ENGLISH )) {
52
+ Properties translatedMessages = new Properties ();
53
+ translatedMessages .load (I18nTestClass .class .getClassLoader ().getResourceAsStream ("Messages_" + locale .toString () + ".properties" ));
54
+ I18nTestClass translatedTestClass = getI18nTestClass (Locale .ENGLISH );
55
+ Set <String > translatedPluralSuffixes = translatedTestClass .getPluralSuffixes ();
56
+
57
+ Set <String > translatedPluralKeys = new HashSet <>();
58
+ Set <String > translatedKeys = new HashSet <>();
59
+
60
+ for (Object objectKey : translatedMessages .keySet ()) {
61
+ String key = (String ) objectKey ;
62
+ Object value = translatedMessages .get (objectKey );
63
+ if (
64
+ value instanceof String &&
65
+ !((String ) value ).trim ().isEmpty ()) {
66
+ if (isPluralKey (key , translatedPluralSuffixes )) {
67
+ final String pluralKeyRoot = getPluralKeyRoot (key , englishPluralSuffixes );
68
+ translatedPluralKeys .add (pluralKeyRoot );
69
+ } else {
70
+ translatedKeys .add (key );
71
+ }
72
+ }
73
+ }
74
+
75
+ Set <String > intersectionKeys = new HashSet <>(englishKeys );
76
+ intersectionKeys .retainAll (translatedKeys );
77
+ Set <String > intersectionPluralKeys = new HashSet <>(englishPluralKeys );
78
+ intersectionPluralKeys .retainAll (translatedPluralKeys );
79
+
80
+ Set <String > missingKeys = new HashSet <>(englishKeys );
81
+ Set <String > missingPluralKeys = new HashSet <>(englishPluralKeys );
82
+
83
+ missingKeys .removeAll (translatedKeys );
84
+ missingPluralKeys .removeAll (translatedPluralKeys );
85
+
86
+ foundKeys .put (locale , intersectionKeys .size ());
87
+ foundPluralKeys .put (locale , intersectionPluralKeys .size ());
88
+
89
+ for (String missingKey : missingKeys ) {
90
+ System .err .println ("Missing key for locale " + locale + ": " + missingKey );
91
+ }
92
+ for (String missingPluralKey : missingPluralKeys ) {
93
+ System .err .println ("Missing plural key for locale " + locale + ": " + missingPluralKey );
94
+ }
95
+ }
96
+ }
97
+
98
+
99
+ PrintStream out = getCSVOutputStream ();
100
+
101
+ printPhraseCoverageCSV (out , foundKeys , foundPluralKeys , englishKeys , englishPluralKeys );
102
+ }
103
+
104
+ private static PrintStream getCSVOutputStream () throws FileNotFoundException {
105
+ String outputFile = System .getenv ("I18N_COVERAGE_FILE" );
106
+
107
+ return outputFile == null
108
+ ? System .out
109
+ : new PrintStream (new File (outputFile ));
110
+ }
111
+
112
+ private static void printPhraseCoverageCSV (PrintStream out , HashMap <Locale , Integer > foundKeys , HashMap <Locale , Integer > foundPluralKeys , Set <String > englishKeys , Set <String > englishPluralKeys ) {
113
+ out .println ("Locale,Complete #,Complete %" );
114
+ for (Locale locale : foundKeys .keySet ()) {
115
+ int singleCount = foundKeys .get (locale );
116
+ int pluralCount = foundPluralKeys .get (locale );
117
+
118
+ int count = singleCount + pluralCount ;
119
+ int total = englishKeys .size () + englishPluralKeys .size ();
120
+
121
+ out .println (locale + "," + count + "," + getPercent ( count , total ));
122
+ }
123
+ }
124
+
125
+ private static String getPercent (int numerator , int denominator ) {
126
+ return (int ) (((double )numerator / denominator ) * 100 ) + "%" ;
127
+ }
128
+
129
+ private String getPluralKeyRoot (String key , Set <String > pluralKeys ) {
130
+ for (String pluralKey : pluralKeys ) {
131
+ final String suffix = I18nBase .KEY_DELIMITER + pluralKey ;
132
+ if (key .endsWith (suffix )) {
133
+ return key .substring (0 , key .lastIndexOf (suffix ));
134
+ }
135
+ }
136
+ throw new IllegalArgumentException (key + " does not terminate with a plural suffix. Available: " + pluralKeys );
137
+ }
138
+
139
+ private boolean isPluralKey (String key , Set <String > pluralKeys ) {
140
+ for (String pluralKey : pluralKeys ) {
141
+ if (key .endsWith (I18nBase .KEY_DELIMITER + pluralKey )) {
142
+ return true ;
143
+ }
144
+ }
145
+ return false ;
146
+ }
147
+
148
+ @ Test
149
+ public void testConstantsCoverage () throws IllegalAccessException {
32
150
33
151
Field [] fields = I18nConstants .class .getDeclaredFields ();
34
152
Map <Locale , I18nBase > testClassMap = new HashMap <>();
@@ -49,7 +167,6 @@ public void testCoverage() throws IllegalAccessException {
49
167
for (Locale locale : locales ) {
50
168
I18nBase base = testClassMap .get (locale );
51
169
52
-
53
170
isSingularPhrase .put (locale , base .messageKeyExistsForLocale (message ));
54
171
isPluralPhrase .put (locale , existsAsPluralPhrase (base , message ));
55
172
}
0 commit comments