chromium/tools/metrics/dwa/gen_builders_test.py

#!/usr/bin/env python3
# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import unittest

import codegen
import builders_template
import decode_template
import dwa_model
import os

_FILE_DIR = os.path.dirname(__file__)


class GenBuildersTest(unittest.TestCase):

  def setUp(self) -> None:
    self.relpath = '.'
    with open(_FILE_DIR + '/dwa.xml') as f:
      self.data = dwa_model.DWA_XML_TYPE.Parse(f.read())
    event = self.data[dwa_model._EVENT_TYPE.tag][0]
    metric = event[dwa_model._METRIC_TYPE.tag][0]
    study = event[dwa_model._STUDY_TYPE.tag][0]
    self.assertIsNotNone(event)
    self.assertIsNotNone(metric)
    self.assertIsNotNone(study)
    self.event_info = codegen.EventInfo(event)
    self.metric_info = codegen.MetricInfo(metric)
    self.study_info = codegen.StudyInfo(study)

  def testBuildersHeaderOutput(self) -> None:
    # Not using codegen.Template.WriteFile to avoid non-deterministic test
    # behaviour after writing to disk.
    builders_header_output = builders_template.HEADER._StampFileCode(
        self.relpath, self.data)
    self.assertIsNotNone(builders_header_output)
    self.assertIn("// Generated from gen_builders.py.  DO NOT EDIT!",
                  builders_header_output)
    self.assertIn("namespace builders", builders_header_output)
    self.assertIn(
        """
class {name} final : public ::dwa::internal::DwaEntryBuilderBase {{
 public:
  explicit {name}();
  {name}({name}&&);
  {name}& operator=({name}&&);
  ~{name}() override;

  static const char kEntryName[];
  static constexpr uint64_t kEntryNameHash = UINT64_C({hash});""".format(
            name=self.event_info.name, hash=self.event_info.hash),
        builders_header_output)

    self.assertIn(
        """
  static const char k{metricName}Name[];
  static constexpr uint64_t k{metricName}NameHash = UINT64_C({metricHash});
  {eventName}& Set{metricName}(int64_t value);
""".format(eventName=self.event_info.name,
           metricName=self.metric_info.name,
           metricHash=self.metric_info.hash), builders_header_output)
    self.assertIn(
        """
  static const char k{studyName}Name[];
  static constexpr uint64_t k{studyName}NameHash = UINT64_C({studyHash});
  {eventName}& Add{studyName}(int64_t value);
""".format(eventName=self.event_info.name,
           studyName=self.study_info.name,
           studyHash=self.study_info.hash), builders_header_output)

  def testBuildersImplementationOutput(self) -> None:
    builders_impl_output = builders_template.IMPL._StampFileCode(
        self.relpath, self.data)
    self.assertIsNotNone(builders_impl_output)
    self.assertIn("// Generated from gen_builders.py.  DO NOT EDIT!",
                  builders_impl_output)
    self.assertIn("namespace builders", builders_impl_output)
    self.assertIn(
        """
const char {name}::kEntryName[] = "{rawName}";
const uint64_t {name}::kEntryNameHash;

{name}::{name}() :
  ::dwa::internal::DwaEntryBuilderBase(kEntryNameHash) {{
}}""".format(name=self.event_info.name, rawName=self.event_info.raw_name),
        builders_impl_output)

    self.assertIn(
        """
const char {eventName}::k{metricName}Name[] = "{metricRawName}";
const uint64_t {eventName}::k{metricName}NameHash;

{eventName}& {eventName}::Set{metricName}(int64_t value) {{
  SetMetricInternal(k{metricName}NameHash, value);
  return *this;
}}
""".format(eventName=self.event_info.name,
           metricName=self.metric_info.name,
           metricRawName=self.metric_info.raw_name), builders_impl_output)
    self.assertIn(
        """
const char {eventName}::k{studyName}Name[] = "{studyRawName}";
const uint64_t {eventName}::k{studyName}NameHash;

{eventName}& {eventName}::Add{studyName}(int64_t value) {{
  AddStudyInternal(k{studyName}NameHash, value);
  return *this;
}}
""".format(eventName=self.event_info.name,
           studyName=self.study_info.name,
           studyRawName=self.study_info.raw_name), builders_impl_output)

  def testDecodeHeaderOutput(self) -> None:
    decode_header_output = decode_template.HEADER._StampFileCode(
        self.relpath, self.data)
    self.assertIsNotNone(decode_header_output)
    self.assertIn("// Generated from gen_builders.py.  DO NOT EDIT!",
                  decode_header_output)
    self.assertIn("namespace builders", decode_header_output)
    self.assertIn(
        """typedef std::map<uint64_t, const char*> MetricDecodeMap;
typedef std::map<uint64_t, const char*> StudyDecodeMap;
struct EntryDecoder {
  const char* name;
  const MetricDecodeMap metric_map;
  const StudyDecodeMap study_map;
};
typedef std::map<uint64_t, EntryDecoder> DecodeMap;
DecodeMap CreateDecodeMap();""", decode_header_output)

  def testDecodeImplementationOutput(self) -> None:
    decode_impl_output = decode_template.IMPL._StampFileCode(
        self.relpath, self.data)
    self.assertIsNotNone(decode_impl_output)
    self.assertIn("// Generated from gen_builders.py.  DO NOT EDIT!",
                  decode_impl_output)
    self.assertIn("namespace builders", decode_impl_output)
    self.assertIn(
        """
    {{{eventName}::k{metricName}NameHash, {eventName}::k{metricName}Name}},""".
        format(eventName=self.event_info.name,
               metricName=self.metric_info.name), decode_impl_output)
    self.assertIn(
        """
    {{{eventName}::k{studyName}NameHash, {eventName}::k{studyName}Name}},""".
        format(eventName=self.event_info.name,
               studyName=self.study_info.name), decode_impl_output)


if __name__ == '__main__':
  unittest.main()