예제 #1
0
 def _generate_policy_map_items(self, rules_map: RulesMap) -> str:
     policy_map_items = ''
     for name, rules in sorted(rules_map.items(),
                               key=lambda x: normalize_name(x[0])):
         policy_map_items += self.ZONE_POLICY_MAP_ITEM.format(
             policyName=normalize_name(name))
     return policy_map_items
예제 #2
0
 def _generate_link_item(self, link_name: str, zone_name: str) -> str:
     return self.ZONE_INFOS_CPP_LINK_ITEM.format(
         scope=self.scope,
         linkFullName=link_name,
         linkNormalizedName=normalize_name(link_name),
         zoneFullName=zone_name,
         zoneNormalizedName=normalize_name(zone_name))
예제 #3
0
 def _generate_info_map_items(self, zones_map: ZonesMap) -> str:
     """Generate a map of (zone_name -> zoneInfo), shorted by name.
     """
     info_map_items = ''
     for zone_name, zones in sorted(zones_map.items(),
                                    key=lambda x: normalize_name(x[0])):
         info_map_items += self.ZONE_INFO_MAP_ITEM.format(
             zoneNormalizedName=normalize_name(zone_name),
             zoneFullName=zone_name)
     return info_map_items
예제 #4
0
    def generate_infos_h(self) -> str:
        info_items = ''
        for zone_name, eras in sorted(self.zones_map.items()):
            info_items += self.ZONE_INFOS_H_INFO_ITEM.format(
                scope=self.scope,
                zoneNormalizedName=normalize_name(zone_name),
                zoneFullName=zone_name)

        removed_info_items = ''
        for zone_name, reasons in sorted(self.removed_zones.items()):
            removed_info_items += self.ZONE_INFOS_H_REMOVED_INFO_ITEM.format(
                zoneFullName=zone_name, reason=', '.join(reasons))

        notable_info_items = ''
        for zone_name, reasons in sorted(self.notable_zones.items()):
            notable_info_items += self.ZONE_INFOS_H_NOTABLE_INFO_ITEM.format(
                zoneFullName=zone_name, reason=', '.join(reasons))

        link_items = ''
        for link_name, zone_name in sorted(self.links_map.items()):
            link_items += self.ZONE_INFOS_H_LINK_ITEM.format(
                scope=self.scope,
                linkNormalizedName=normalize_name(link_name),
                linkFullName=link_name,
                zoneFullName=zone_name)

        removed_link_items = ''
        for link_name, reasons in sorted(self.removed_links.items()):
            removed_link_items += self.ZONE_INFOS_H_REMOVED_LINK_ITEM.format(
                linkFullName=link_name, reason=', '.join(reasons))

        notable_link_items = ''
        for link_name, reasons in sorted(self.notable_links.items()):
            notable_link_items += self.ZONE_INFOS_H_NOTABLE_LINK_ITEM.format(
                linkFullName=link_name, reason=', '.join(reasons))

        return self.ZONE_INFOS_H_FILE.format(
            invocation=self.invocation,
            tz_version=self.tz_version,
            scope=self.scope,
            dbNamespace=self.db_namespace,
            dbHeaderNamespace=self.db_header_namespace,
            tz_files=', '.join(self.tz_files),
            numInfos=len(self.zones_map),
            infoItems=info_items,
            numLinks=len(self.links_map),
            linkItems=link_items,
            numRemovedInfos=len(self.removed_zones),
            removedInfoItems=removed_info_items,
            numNotableInfos=len(self.notable_zones),
            notableInfoItems=notable_info_items,
            numRemovedLinks=len(self.removed_links),
            removedLinkItems=removed_link_items,
            numNotableLinks=len(self.notable_links),
            notableLinkItems=notable_link_items)
예제 #5
0
    def _generate_test_cases(self, test_data: TestData) -> str:
        dst_blacklist: Set[str] = (set(
            self.validation_data.get('dst_blacklist') or []))
        has_valid_abbrev = self.validation_data['has_valid_abbrev']
        has_valid_dst = self.validation_data['has_valid_dst']
        test_cases = ''
        for zone_name, _ in sorted(test_data.items()):
            normalized_name = normalize_name(zone_name)
            test_dst = ('true' if has_valid_dst and
                        (zone_name not in dst_blacklist) else 'false')
            test_dst_comment = (' BLACKLISTED' if has_valid_dst and
                                (zone_name in dst_blacklist) else '')
            test_abbrev = 'true' if has_valid_abbrev else 'false'

            test_case = f"""\
testF({self.test_class}, {normalized_name}) {{
  assertValid(
     &kZone{normalized_name},
     &kValidationData{normalized_name},
     {test_dst} /*validateDst{test_dst_comment}*/,
     {test_abbrev} /*validateAbbrev*/);
}}
"""
            test_cases += test_case
        return test_cases
예제 #6
0
    def generate_policies_h(self) -> str:
        policy_items = ''
        for name, rules in sorted(self.rules_map.items()):
            policy_items += self.ZONE_POLICIES_H_POLICY_ITEM.format(
                policyName=normalize_name(name),
                scope=self.scope)

        removed_policy_items = ''
        for name, reasons in sorted(self.removed_policies.items()):
            removed_policy_items += \
                self.ZONE_POLICIES_H_REMOVED_POLICY_ITEM.format(
                    policyName=name,
                    policyReason=', '.join(reasons))

        notable_policy_items = ''
        for name, reasons in sorted(self.notable_policies.items()):
            notable_policy_items += \
                self.ZONE_POLICIES_H_NOTABLE_POLICY_ITEM.format(
                    policyName=name,
                    policyReason=', '.join(reasons))

        return self.ZONE_POLICIES_H_FILE.format(
            invocation=self.invocation,
            tz_version=self.tz_version,
            dbNamespace=self.db_namespace,
            dbHeaderNamespace=self.db_header_namespace,
            tz_files=', '.join(self.tz_files),
            numPolicies=len(self.rules_map),
            policyItems=policy_items,
            numRemovedPolicies=len(self.removed_policies),
            removedPolicyItems=removed_policy_items,
            numNotablePolicies=len(self.notable_policies),
            notablePolicyItems=notable_policy_items)
예제 #7
0
    def _generate_test_cases(self, test_data: TestData) -> str:
        has_valid_abbrev = self.validation_data['has_valid_abbrev']
        has_valid_dst = self.validation_data['has_valid_dst']
        test_cases = ''
        for zone_name, _ in sorted(test_data.items()):
            normalized_name = normalize_name(zone_name)

            (
                dst_validation_scope,
                dst_validation_comment,
            ) = _get_validation_scope(
                has_valid_dst,
                self.blacklist.get(zone_name),
            )
            (
                abbrev_validation_scope,
                abbrev_validation_comment,
            ) = _get_validation_scope(
                has_valid_abbrev,
                self.blacklist.get(zone_name),
            )

            test_case = f"""\
testF({self.test_class}, {normalized_name}) {{
  assertValid(
     &kZone{normalized_name},
     &kValidationData{normalized_name},
     {dst_validation_scope} /*dstValidationScope{dst_validation_comment}*/,
     {abbrev_validation_scope} \
/*abbrevValidationScope{abbrev_validation_comment}*/);
}}
"""
            test_cases += test_case
        return test_cases
예제 #8
0
 def _generate_validation_data_h_items(self, test_data: TestData) -> str:
     validation_items = ''
     for zone_name, test_items in sorted(test_data.items()):
         validation_items += self.VALIDATION_DATA_H_ITEM.format(
             validationDataClass=self.validation_data_class,
             zoneNormalizedName=normalize_name(zone_name))
     return validation_items
예제 #9
0
    def _generate_validation_data_cpp_items(self, test_data: TestData) -> str:
        validation_items = ''
        for zone_name, test_items in sorted(test_data.items()):
            test_items_string = self._generate_validation_data_cpp_test_items(
                zone_name, test_items)
            normalized_name = normalize_name(zone_name)

            validation_item = f"""\
//---------------------------------------------------------------------------
// Zone name: {zone_name}
//---------------------------------------------------------------------------

static const testing::ValidationItem kValidationItems{normalized_name}[] = {{
  //     epoch,  utc,  dst,    y,  m,  d,  h,  m,  s, abbrev
{test_items_string}
}};

const testing::ValidationData kValidationData{normalized_name} = {{
  {len(test_items)} /*numItems*/,
  kValidationItems{normalized_name} /*items*/,
}};

"""
            validation_items += validation_item
        return validation_items
예제 #10
0
    def _generate_infos(self) -> None:
        for zone_name, eras in self.zones_map.items():
            zone_eras: List[ZoneEra] = []
            for era in eras:
                policy_name = era['rules']
                zone_policy: Union[ZonePolicy, str]
                if policy_name in ['-', ':']:
                    zone_policy = policy_name
                else:
                    policy_name = normalize_name(policy_name)
                    zone_policy = self.zone_policies[policy_name]

                # yapf: disable
                zone_eras.append({
                    'offsetSeconds': era['offsetSecondsTruncated'],
                    'zonePolicy': zone_policy,
                    'rulesDeltaSeconds': era['rulesDeltaSecondsTruncated'],
                    'format': era['format'],
                    'untilYear': era['untilYear'],
                    'untilMonth': era['untilMonth'],
                    'untilDay': era['untilDay'],
                    'untilSeconds': era['untilSecondsTruncated'],
                    'untilTimeSuffix': era['untilTimeSuffix'],
                })
                # yapf: enable
            self.zone_infos[zone_name] = {'name': zone_name, 'eras': zone_eras}
예제 #11
0
 def _generate_test_cases(self, test_data: TestData) -> str:
     test_cases = ''
     for zone_name, _ in sorted(test_data.items()):
         test_case = self.TEST_CASE.format(
             dbNamespace=self.db_namespace,
             testClass=self.test_class,
             zoneNormalizedName=normalize_name(zone_name))
         test_cases += test_case
     return test_cases
예제 #12
0
 def _generate_removed_policy_items(
     self,
     removed_policies: CommentsMap,
 ) -> str:
     removed_policy_items = ''
     for name, reason in sorted(removed_policies.items()):
         removed_policy_items += (self.ZONE_REMOVED_POLICY_ITEM.format(
             policyName=normalize_name(name), policyReason=reason))
     return removed_policy_items
예제 #13
0
    def _generate_validation_data_h_items(self, test_data: TestData) -> str:
        validation_items = ''
        for zone_name, test_items in sorted(test_data.items()):
            normalized_name = normalize_name(zone_name)
            validation_items += f"""\
extern const testing::ValidationData kValidationData{normalized_name};
"""

        return validation_items
예제 #14
0
 def _generate_notable_policy_items(
     self,
     notable_policies: CommentsMap,
 ) -> str:
     notable_policy_items = ''
     for name, reason in sorted(notable_policies.items()):
         notable_policy_items += (self.ZONE_NOTABLE_POLICY_ITEM.format(
             policyName=normalize_name(name), policyReason=reason))
     return notable_policy_items
예제 #15
0
 def _generate_policy_item(self, name: str,
                           rules: List[ZoneRuleRaw]) -> str:
     rule_items = ''
     for rule in rules:
         rule_items += self.ZONE_RULE_ITEM.format(
             policyName=normalize_name(name),
             rawLine=normalize_raw(rule['rawLine']),
             fromYear=rule['fromYear'],
             toYear=rule['toYear'],
             inMonth=rule['inMonth'],
             onDayOfWeek=rule['onDayOfWeek'],
             onDayOfMonth=rule['onDayOfMonth'],
             atSeconds=rule['atSecondsTruncated'],
             atTimeSuffix=rule['atTimeSuffix'],
             deltaSeconds=rule['deltaSecondsTruncated'],
             letter=rule['letter'])
     return self.ZONE_POLICY_ITEM.format(policyName=normalize_name(name),
                                         numRules=len(rules),
                                         ruleItems=rule_items)
예제 #16
0
 def _generate_validation_data_cpp_items(self, test_data: TestData) -> str:
     validation_items = ''
     for zone_name, test_items in sorted(test_data.items()):
         test_items_string = self._generate_validation_data_cpp_test_items(
             zone_name, test_items)
         validation_item = self.VALIDATION_DATA_CPP_ITEM.format(
             validationDataClass=self.validation_data_class,
             zoneFullName=zone_name,
             zoneNormalizedName=normalize_name(zone_name),
             testItems=test_items_string)
         validation_items += validation_item
     return validation_items
예제 #17
0
    def _generate_era_item(
        self, zone_name: str, era: ZoneEraRaw
    ) -> Tuple[str, int]:
        policy_name = era['rules']
        if policy_name == '-' or policy_name == ':':
            zone_policy = 'nullptr'
            delta_seconds = era['rulesDeltaSecondsTruncated']
        else:
            zone_policy = '&kPolicy%s' % normalize_name(policy_name)
            delta_seconds = 0

        if self.scope == 'extended':
            offset_code, delta_code = _to_extended_offset_and_delta(
                era['offsetSecondsTruncated'], delta_seconds)
        else:
            offset_code = div_to_zero(era['offsetSecondsTruncated'], 900)
            delta_code = str(div_to_zero(delta_seconds, 900))

        until_year = era['untilYear']
        if until_year == MAX_UNTIL_YEAR:
            until_year_tiny = MAX_UNTIL_YEAR_TINY
        else:
            until_year_tiny = until_year - EPOCH_YEAR

        until_month = era['untilMonth']
        if not until_month:
            until_month = 1

        until_day = era['untilDay']
        if not until_day:
            until_day = 1

        until_time_code, until_time_modifier = _to_code_and_modifier(
            era['untilSecondsTruncated'], era['untilTimeSuffix'], self.scope)

        # Replace %s with just a % for C++
        format = era['format'].replace('%s', '%')
        string_length = len(format) + 1

        era_item = self.ZONE_INFOS_CPP_ERA_ITEM.format(
            rawLine=normalize_raw(era['rawLine']),
            offsetCode=offset_code,
            deltaCode=delta_code,
            zonePolicy=zone_policy,
            format=format,
            untilYearTiny=until_year_tiny,
            untilMonth=until_month,
            untilDay=until_day,
            untilTimeCode=until_time_code,
            untilTimeModifier=until_time_modifier)

        return (era_item, string_length)
예제 #18
0
    def _generate_info_item(
        self,
        zone_name: str,
        eras: List[ZoneEraRaw],
    ) -> str:
        era_items = ''
        for era in eras:
            era_items += self._generate_era_item(era)

        return self.ZONE_INFO_ITEM.format(
            zoneFullName=zone_name,
            zoneNormalizedName=normalize_name(zone_name),
            numEras=len(eras),
            eraItems=era_items)
예제 #19
0
 def generate_registry_cpp(self) -> str:
     zone_registry_items = ''
     for zone_name, eras in sorted(self.zones_map.items()):
         name = normalize_name(zone_name)
         zone_registry_items += f'  &kZone{name}, // {zone_name}\n'
     return self.ZONE_REGISTRY_CPP_FILE.format(
         invocation=self.invocation,
         tz_version=self.tz_version,
         scope=self.scope,
         dbNamespace=self.db_namespace,
         dbHeaderNamespace=self.db_header_namespace,
         numZones=len(self.zones_map),
         zoneRegistryItems=zone_registry_items,
         progmem='ACE_TIME_PROGMEM')
예제 #20
0
    def _generate_era_item(self, era: ZoneEraRaw) -> str:
        policy_name = era['rules']
        if policy_name in ['-', ':']:
            zone_policy = "'%s'" % policy_name
        else:
            zone_policy = 'ZONE_POLICY_%s' % normalize_name(policy_name)

        return self.ZONE_ERA_ITEM.format(
            rawLine=normalize_raw(era['rawLine']),
            offsetSeconds=era['offsetSecondsTruncated'],
            zonePolicy=zone_policy,
            rulesDeltaSeconds=era['rulesDeltaSecondsTruncated'],
            format=era['format'],  # preserve the %s
            untilYear=era['untilYear'],
            untilMonth=era['untilMonth'],
            untilDay=era['untilDay'],
            untilSeconds=era['untilSecondsTruncated'],
            untilTimeSuffix=era['untilTimeSuffix'])
예제 #21
0
    def _generate_info_item(
        self,
        zone_name: str,
        eras: List[ZoneEraRaw],
    ) -> Tuple[str, int]:
        era_items = ''
        string_length = 0
        for era in eras:
            (era_item, length) = self._generate_era_item(zone_name, era)
            era_items += era_item
            string_length += length

        string_length += len(zone_name) + 1
        num_eras = len(eras)
        memory8 = (
            string_length
            + num_eras * self.SIZEOF_ZONE_ERA_8
            + 1 * self.SIZEOF_ZONE_INFO_8)
        memory32 = (
            string_length
            + num_eras * self.SIZEOF_ZONE_ERA_32
            + 1 * self.SIZEOF_ZONE_INFO_32)

        transition_buf_size = self.buf_sizes[zone_name]

        info_item = self.ZONE_INFOS_CPP_INFO_ITEM.format(
            scope=self.scope,
            zoneFullName=zone_name,
            zoneNormalizedName=normalize_name(zone_name),
            zoneNameHash=hash_name(zone_name),
            transitionBufSize=transition_buf_size,
            numEras=num_eras,
            stringLength=string_length,
            memory8=memory8,
            memory32=memory32,
            eraItems=era_items,
            progmem='ACE_TIME_PROGMEM')
        return (info_item, string_length)
예제 #22
0
    def _generate_policies(self) -> None:
        for name, rules in self.rules_map.items():
            policy_rules: List[ZoneRule] = []
            for rule in rules:
                # yapf: disable
                policy_rules.append({
                    'fromYear': rule['fromYear'],
                    'toYear': rule['toYear'],
                    'inMonth': rule['inMonth'],
                    'onDayOfWeek': rule['onDayOfWeek'],
                    'onDayOfMonth': rule['onDayOfMonth'],
                    'atSeconds': rule['atSecondsTruncated'],
                    'atTimeSuffix': rule['atTimeSuffix'],
                    'deltaSeconds': rule['deltaSecondsTruncated'],
                    'letter': rule['letter']
                })
                # yapf: enable

            normalized_name = normalize_name(name)
            self.zone_policies[normalized_name] = {
                'name': name,  # policy name
                'rules': policy_rules
            }
예제 #23
0
    def _generate_policy_item(
        self,
        name: str,
        rules: List[ZoneRuleRaw],
        indexed_letters: Optional[IndexedLetters],
    ) -> Tuple[str, int, int]:

        # Generate kZoneRules*[]
        rule_items = ''
        for rule in rules:
            at_time_code, at_time_modifier = _to_code_and_modifier(
                rule['atSecondsTruncated'], rule['atTimeSuffix'], self.scope)

            if self.scope == 'extended':
                delta_code = _to_extended_delta_code(
                    rule['deltaSecondsTruncated'])
            else:
                delta_code = str(div_to_zero(
                    rule['deltaSecondsTruncated'], 900
                ))

            from_year = rule['fromYear']
            from_year_tiny = to_tiny_year(from_year)
            to_year = rule['toYear']
            to_year_tiny = to_tiny_year(to_year)

            # Single-character 'letter' values are represented as themselves
            # using the C++ 'char' type ('A'-'Z'). But some 'letter' fields hold
            # a multi-character string. We can encode these multi-character
            # strings as an index into an array of NUL-terminated strings.
            # ASCII codes less than 32 (space) are non-printable control
            # characters so they will not collide with the printable characters
            # 'A' - 'Z'. Therefore we can hold to up to 31 multi-character
            # strings per-zone. In practice, for a single zone, the maximum
            # number of multi-character strings that I've seen is 2.
            if len(rule['letter']) == 1:
                letter = "'%s'" % rule['letter']
                letterComment = ''
            elif len(rule['letter']) > 1:
                letters = cast(IndexedLetters, indexed_letters)
                index = letters[rule['letter']]
                if index >= 32:
                    raise Exception('Number of indexed letters >= 32')
                letter = str(index)
                letterComment = ('; "%s"' % rule['letter'])
            else:
                raise Exception(
                    'len(%s) == 0; should not happen'
                    % rule['letter'])

            rule_items += self.ZONE_POLICIES_CPP_RULE_ITEM.format(
                rawLine=normalize_raw(rule['rawLine']),
                fromYearTiny=from_year_tiny,
                toYearTiny=to_year_tiny,
                inMonth=rule['inMonth'],
                onDayOfWeek=rule['onDayOfWeek'],
                onDayOfMonth=rule['onDayOfMonth'],
                atTimeCode=at_time_code,
                atTimeModifier=at_time_modifier,
                deltaCode=delta_code,
                letter=letter,
                letterComment=letterComment)

        # Generate kLetters*[]
        policyName = normalize_name(name)
        numLetters = len(indexed_letters) if indexed_letters else 0
        memoryLetters8 = 0
        memoryLetters32 = 0
        if numLetters:
            letters = cast(IndexedLetters, indexed_letters)
            letterArrayRef = 'kLetters%s' % policyName
            letterItems = ''
            for name, index in letters.items():
                letterItems += ('  /*%d*/ "%s",\n' % (index, name))
                memoryLetters8 += len(name) + 1 + 2  # NUL terminated
                memoryLetters32 += len(name) + 1 + 4  # NUL terminated
            letterArray = self.ZONE_POLICIES_LETTER_ARRAY.format(
                policyName=policyName,
                letterItems=letterItems,
                progmem='ACE_TIME_PROGMEM')
        else:
            letterArrayRef = 'nullptr'
            letterArray = ''

        # Calculate the memory consumed by structs and arrays
        num_rules = len(rules)
        memory8 = (
            1 * self.SIZEOF_ZONE_POLICY_8
            + num_rules * self.SIZEOF_ZONE_RULE_8
            + memoryLetters8)
        memory32 = (
            1 * self.SIZEOF_ZONE_POLICY_32
            + num_rules * self.SIZEOF_ZONE_RULE_32
            + memoryLetters32)

        policy_item = self.ZONE_POLICIES_CPP_POLICY_ITEM.format(
            scope=self.scope,
            policyName=policyName,
            numRules=num_rules,
            memory8=memory8,
            memory32=memory32,
            ruleItems=rule_items,
            numLetters=numLetters,
            letterArrayRef=letterArrayRef,
            letterArray=letterArray,
            progmem='ACE_TIME_PROGMEM')

        return (policy_item, memory8, memory32)