Test for consistency of KNOWN_CODENAMES.

We want all Q+ codenames and only those  to be listed in the set.

Bug: 211747008
Test: atest android.os.cts.BuildTest#testBuildCodenameConstants
Change-Id: Id721ad416194927f0d883d7d924a2aa48705dcd4
diff --git a/tests/tests/os/src/android/os/cts/BuildTest.java b/tests/tests/os/src/android/os/cts/BuildTest.java
index 38e1999..8a55fe5 100644
--- a/tests/tests/os/src/android/os/cts/BuildTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildTest.java
@@ -35,6 +35,7 @@
 import java.util.Scanner;
 import java.util.Set;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 public class BuildTest extends TestCase {
 
@@ -292,6 +293,10 @@
         List<String> activeCodenames = Arrays.asList(ACTIVE_CODENAMES);
         // Make the codenames uppercase to match the field names.
         activeCodenames.replaceAll(String::toUpperCase);
+        Set<String> knownCodenames = Build.VERSION.KNOWN_CODENAMES.stream()
+                .map(String::toUpperCase)
+                .collect(Collectors.toSet());
+        HashSet<String> declaredCodenames = new HashSet<>();
         for (Field field : fields) {
             if (field.getType().equals(int.class) && Modifier.isStatic(field.getModifiers())) {
                 String fieldName = field.getName();
@@ -301,22 +306,40 @@
                 } catch (IllegalAccessException e) {
                     throw new AssertionError(e.getMessage());
                 }
+                declaredCodenames.add(fieldName);
                 if (fieldName.equals("CUR_DEVELOPMENT")) {
                     // It should be okay to change the value of this constant in future, but it
                     // should at least be a conscious decision.
                     assertEquals(10000, fieldValue);
-                } else if (activeCodenames.contains(fieldName)) {
-                    // This is the current development version. Note that fieldName can
-                    // become < CUR_DEVELOPMENT before CODENAME becomes "REL", so we
-                    // can't assertEquals(CUR_DEVELOPMENT, fieldValue) here.
-                    assertTrue("Expected " + fieldName + " value to be <= " + CUR_DEVELOPMENT
-                            + ", got " + fieldValue, fieldValue <= CUR_DEVELOPMENT);
                 } else {
-                    assertTrue("Expected " + fieldName + " value to be < " + CUR_DEVELOPMENT
-                            + ", got " + fieldValue, fieldValue < CUR_DEVELOPMENT);
+                    if (activeCodenames.contains(fieldName)) {
+                        // This is the current development version. Note that fieldName can
+                        // become < CUR_DEVELOPMENT before CODENAME becomes "REL", so we
+                        // can't assertEquals(CUR_DEVELOPMENT, fieldValue) here.
+                        assertTrue("Expected " + fieldName + " value to be <= " + CUR_DEVELOPMENT
+                                + ", got " + fieldValue, fieldValue <= CUR_DEVELOPMENT);
+                    } else {
+                        assertTrue("Expected " + fieldName + " value to be < " + CUR_DEVELOPMENT
+                                + ", got " + fieldValue, fieldValue < CUR_DEVELOPMENT);
+                    }
+                    // KNOWN_CODENAMES only tracks Q+ codenames
+                    if (fieldValue >= Build.VERSION_CODES.Q) {
+                        // Remove all underscores to match build level codenames, e.g. S_V2 is Sv2.
+                        String name = fieldName.replaceAll("_", "");
+                        declaredCodenames.add(name);
+                        assertTrue("Expected " + name
+                                        + " to be declared in Build.VERSION.KNOWN_CODENAMES",
+                                knownCodenames.contains(name));
+                    }
                 }
             }
         }
+
+        HashSet<String> diff = new HashSet<>(knownCodenames);
+        diff.removeAll(declaredCodenames);
+        assertTrue(
+                "Expected all elements in Build.VERSION.KNOWN_CODENAMES to be declared in"
+                        + " Build.VERSION_CODES, found " + diff, diff.isEmpty());
     }
 
     /**