Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/cc/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 21 kB image not shown  

Quelle  testing.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cc

import (
 "path/filepath"
 "testing"

 "android/soong/android"
 "android/soong/genrule"
)

func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
 RegisterPrebuiltBuildComponents(ctx)
 RegisterCCBuildComponents(ctx)
 RegisterBinaryBuildComponents(ctx)
 RegisterLibraryBuildComponents(ctx)
 RegisterLibraryHeadersBuildComponents(ctx)

 ctx.RegisterModuleType("prebuilt_build_tool", android.NewPrebuiltBuildTool)
 ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
 ctx.RegisterModuleType("cc_cmake_snapshot", CmakeSnapshotFactory)
 ctx.RegisterModuleType("cc_object", ObjectFactory)
 ctx.RegisterModuleType("cc_genrule", GenRuleFactory)
 ctx.RegisterModuleType("cc_genrule_defaults", genruleDefaultsFactory)
 ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
 ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
 ctx.RegisterModuleType("all_artless_denylists", AllArtlessDenylistsFactory)
 ctx.RegisterModuleType("all_artless_blocked_symbol_files", AllArtlessBlockedSymbolFilesFactory)
}

func GatherRequiredDepsForTest(oses ...android.OsType) string {
 ret := commonDefaultModules()

 supportLinuxBionic := false
 for _, os := range oses {
  if os == android.Windows {
   ret += withWindowsModules()
  }
  if os == android.LinuxBionic {
   supportLinuxBionic = true
   ret += withLinuxBionic()
  }
 }

 if !supportLinuxBionic {
  ret += withoutLinuxBionic()
 }

 return ret
}

func commonDefaultModules() string {
 return `
  cc_defaults {
   name: "toolchain_libs_defaults",
   host_supported: true,
   vendor_available: true,
   product_available: true,
   recovery_available: true,
   no_libcrt: true,
   sdk_version: "minimum",
   nocrt: true,
   no_crt_pad_segment: true,
   system_shared_libs: [],
   stl: "none",
   check_elf_files: false,
   sanitize: {
    never: true,
   },
   apex_available: [
    "//apex_available:anyapex",
    "//apex_available:platform",
   ],
  }

  cc_prebuilt_library_static {
   name: "libcompiler_rt-extras",
   defaults: ["toolchain_libs_defaults"],
   vendor_ramdisk_available: true,
   srcs: [""],
  }

  cc_prebuilt_library_static {
   name: "libclang_rt.builtins",
   defaults: ["toolchain_libs_defaults"],
   host_supported: true,
         vendor_available: true,
   vendor_ramdisk_available: true,
   native_bridge_supported: true,
   srcs: [""],
  }

  cc_prebuilt_library_shared {
   name: "libclang_rt.hwasan",
   defaults: ["toolchain_libs_defaults"],
   srcs: [""],
   double_loadable: true,
  }

  cc_prebuilt_library_static {
   name: "libunwind",
   defaults: [
    "linux_bionic_supported",
    "toolchain_libs_defaults",
   ],
   vendor_ramdisk_available: true,
   native_bridge_supported: true,
   srcs: [""],
  }

  cc_prebuilt_library_static {
   name: "libclang_rt.fuzzer",
   defaults: [
    "linux_bionic_supported",
    "toolchain_libs_defaults",
   ],
   srcs: [""],
  }

  // Needed for sanitizer
  cc_prebuilt_library_shared {
   name: "libclang_rt.ubsan_standalone",
   defaults: ["toolchain_libs_defaults"],
   double_loadable: true,
   srcs: [""],
  }

  cc_prebuilt_library_static {
   name: "libclang_rt.ubsan_standalone.static",
   defaults: ["toolchain_libs_defaults"],
   srcs: [""],
  }

  cc_prebuilt_library_static {
   name: "libclang_rt.ubsan_minimal",
   defaults: ["toolchain_libs_defaults"],
   host_supported: true,
   target: {
    android_arm64: {
     srcs: ["libclang_rt.ubsan_minimal.android_arm64.a"],
    },
    android_arm: {
     srcs: ["libclang_rt.ubsan_minimal.android_arm.a"],
    },
    linux_glibc_x86_64: {
     srcs: ["libclang_rt.ubsan_minimal.x86_64.a"],
    },
    linux_glibc_x86: {
     srcs: ["libclang_rt.ubsan_minimal.x86.a"],
    },
    linux_musl_x86_64: {
     srcs: ["libclang_rt.ubsan_minimal.x86_64.a"],
    },
    linux_musl_x86: {
     srcs: ["libclang_rt.ubsan_minimal.x86.a"],
    },
   },
  }

  cc_library {
   name: "libc",
   defaults: ["linux_bionic_supported"],
   no_libcrt: true,
   nocrt: true,
   stl: "none",
   system_shared_libs: [],
   recovery_available: true,
   stubs: {
    versions: ["27", "28", "29"],
   },
   llndk: {
    symbol_file: "libc.map.txt",
   },
  }
  cc_library {
   name: "libm",
   defaults: ["linux_bionic_supported"],
   no_libcrt: true,
   nocrt: true,
   stl: "none",
   system_shared_libs: [],
   recovery_available: true,
   stubs: {
    versions: ["27", "28", "29"],
   },
   apex_available: [
    "//apex_available:platform",
    "//apex_available:anyapex",
   ],
   llndk: {
    symbol_file: "libm.map.txt",
   },
  }

  // Coverage libraries
  cc_library {
   name: "libprofile-extras",
   vendor_available: true,
   vendor_ramdisk_available: true,
   product_available: true,
   recovery_available: true,
   native_coverage: false,
   system_shared_libs: [],
   stl: "none",
  }
  cc_library {
   name: "libprofile-clang-extras",
   vendor_available: true,
   vendor_ramdisk_available: true,
   product_available: true,
   recovery_available: true,
   native_coverage: false,
   system_shared_libs: [],
   stl: "none",
  }
  cc_library {
   name: "libprofile-extras_ndk",
   vendor_available: true,
   product_available: true,
   native_coverage: false,
   system_shared_libs: [],
   stl: "none",
   sdk_version: "current",
  }
  cc_library {
   name: "libprofile-clang-extras_ndk",
   vendor_available: true,
   product_available: true,
   native_coverage: false,
   system_shared_libs: [],
   stl: "none",
   sdk_version: "current",
  }

  cc_library {
   name: "libdl",
   defaults: ["linux_bionic_supported"],
   no_libcrt: true,
   nocrt: true,
   stl: "none",
   system_shared_libs: [],
   recovery_available: true,
   stubs: {
    versions: ["27", "28", "29"],
   },
   apex_available: [
    "//apex_available:platform",
    "//apex_available:anyapex",
   ],
   llndk: {
    symbol_file: "libdl.map.txt",
   },
  }
  cc_library {
   name: "libft2",
   no_libcrt: true,
   nocrt: true,
   system_shared_libs: [],
   recovery_available: true,
   llndk: {
    symbol_file: "libft2.map.txt",
    private: true,
   }
  }
  cc_library {
   name: "libc++_static",
   no_libcrt: true,
   nocrt: true,
   system_shared_libs: [],
   stl: "none",
   vendor_available: true,
   vendor_ramdisk_available: true,
   product_available: true,
   recovery_available: true,
   host_supported: true,
   min_sdk_version: "29",
   apex_available: [
    "//apex_available:platform",
    "//apex_available:anyapex",
   ],
  }
  cc_library {
   name: "libc++",
   no_libcrt: true,
   nocrt: true,
   system_shared_libs: [],
   stl: "none",
   vendor_available: true,
   vendor_ramdisk_available: true,
   product_available: true,
   recovery_available: true,
   host_supported: true,
   min_sdk_version: "29",
   double_loadable: true,
   apex_available: [
    "//apex_available:platform",
    "//apex_available:anyapex",
   ],
  }
  cc_library {
   name: "ndk_libc++_shared",
   export_include_dirs: ["ndk_libc++_shared_include_dirs"],
   no_libcrt: true,
   nocrt: true,
   system_shared_libs: [],
   stl: "none",
   vendor_available: true,
   vendor_ramdisk_available: true,
   product_available: true,
   recovery_available: true,
   host_supported: false,
   sdk_version: "minimum",
   double_loadable: true,
   apex_available: [
    "//apex_available:platform",
    "//apex_available:anyapex",
   ],
  }
  cc_library {
   name: "libc++demangle",
   no_libcrt: true,
   nocrt: true,
   system_shared_libs: [],
   stl: "none",
   host_supported: false,
   vendor_available: true,
   vendor_ramdisk_available: true,
   product_available: true,
   recovery_available: true,
   min_sdk_version: "29",
   apex_available: [
    "//apex_available:platform",
    "//apex_available:anyapex",
   ],
  }

  cc_defaults {
   name: "crt_defaults",
   defaults: ["linux_bionic_supported"],
   recovery_available: true,
   vendor_available: true,
   vendor_ramdisk_available: true,
   product_available: true,
   native_bridge_supported: true,
   stl: "none",
   min_sdk_version: "16",
   crt: true,
   system_shared_libs: [],
   apex_available: [
    "//apex_available:platform",
    "//apex_available:anyapex",
   ],
  }

  cc_object {
   name: "crtbegin_so",
   defaults: ["crt_defaults"],
   srcs: ["crtbegin_so.c"],
   objs: ["crtbrand"],
  }

  cc_object {
   name: "crtbegin_dynamic",
   defaults: ["crt_defaults"],
   srcs: ["crtbegin.c"],
   objs: ["crtbrand"],
  }

  cc_object {
   name: "crtbegin_static",
   defaults: ["crt_defaults"],
   srcs: ["crtbegin.c"],
   objs: ["crtbrand"],
  }

  cc_object {
   name: "crtend_so",
   defaults: ["crt_defaults"],
   srcs: ["crtend_so.c"],
   objs: ["crtbrand"],
  }

  cc_object {
   name: "crtend_android",
   defaults: ["crt_defaults"],
   srcs: ["crtend.c"],
   objs: ["crtbrand"],
  }

  cc_object {
   name: "crt_pad_segment",
   defaults: ["crt_defaults"],
  }

  cc_object {
   name: "crtbrand",
   defaults: ["crt_defaults"],
   srcs: ["crtbrand.c"],
  }

  cc_library {
   name: "libprotobuf-cpp-lite",
  }

  cc_library_headers {
   name: "liblog_headers",
   sdk_version: "minimum",
  }

  ndk_library {
   name: "libc",
   first_version: "minimum",
   symbol_file: "libc.map.txt",
  }

  ndk_library {
   name: "libm",
   first_version: "minimum",
   symbol_file: "libm.map.txt",
  }

  ndk_library {
   name: "libdl",
   first_version: "minimum",
   symbol_file: "libdl.map.txt",
  }

  cc_library_static {
   name: "libgoogle-benchmark",
   sdk_version: "current",
   stl: "none",
   system_shared_libs: [],
  }

  cc_library_static {
   name: "note_memtag_heap_async",
  }

  cc_library_static {
   name: "note_memtag_heap_sync",
  }

  cc_library {
   name: "libc_musl",
   host_supported: true,
   no_libcrt: true,
   nocrt: true,
   system_shared_libs: [],
   stl: "none",
  }

  cc_library_static {
   name: "libgtest",
   target: {
    linux_bionic: {
     enabled: true,
    },
   },
   host_supported: true,
   vendor_available: true,
   product_available: true,
   cmake_snapshot_supported: true,
   rtti: true,
  }

  cc_library_static {
   name: "libgtest_main",
   target: {
    linux_bionic: {
     enabled: true,
    },
   },
   host_supported: true,
   vendor_available: true,
   product_available: true,
   cmake_snapshot_supported: true,
  }

  cc_library_static {
   name: "libFuzzer_mte_crash_handler",
   stl: "none",
   system_shared_libs: [],
  }
 `
}

func withWindowsModules() string {
 return `
  cc_prebuilt_library_static {
   name: "libwinpthread",
   host_supported: true,
   enabled: false,
   target: {
    windows: {
     enabled: true,
    },
   },
   stl: "none",
   srcs:[""],
  }
  `
}

func withLinuxBionic() string {
 return `
    cc_binary {
     name: "linker",
     defaults: ["linux_bionic_supported"],
     recovery_available: true,
     stl: "none",
     nocrt: true,
     static_executable: true,
     native_coverage: false,
     system_shared_libs: [],
    }

    cc_genrule {
     name: "host_bionic_linker_script",
     host_supported: true,
     device_supported: false,
     target: {
      host: {
       enabled: false,
      },
      linux_bionic: {
       enabled: true,
      },
     },
     out: ["linker.script"],
    }

    cc_defaults {
     name: "linux_bionic_supported",
     host_supported: true,
     target: {
      host: {
       enabled: false,
      },
      linux_bionic: {
       enabled: true,
      },
     },
    }
   `
}

func withoutLinuxBionic() string {
 return `
   cc_defaults {
    name: "linux_bionic_supported",
   }
  `
}

func GatherRequiredFilesForTest(fs map[string][]byte) {
}

// The directory in which cc linux bionic default modules will be defined.
//
// Placing them here ensures that their location does not conflict with default test modules
// defined by other packages.
const linuxBionicDefaultsPath = "defaults/cc/linux-bionic/Android.bp"

// The directory in which the default cc common test modules will be defined.
//
// Placing them here ensures that their location does not conflict with default test modules
// defined by other packages.
const DefaultCcCommonTestModulesDir = "defaults/cc/common/"

// Test fixture preparer that will register most cc build components.
//
// Singletons and mutators should only be added here if they are needed for a majority of cc
// module types, otherwise they should be added under a separate preparer to allow them to be
// selected only when needed to reduce test execution time.
//
// Module types do not have much of an overhead unless they are used so this should include as many
// module types as possible. The exceptions are those module types that require mutators and/or
// singletons in order to function in which case they should be kept together in a separate
// preparer.
var PrepareForTestWithCcBuildComponents = android.GroupFixturePreparers(
 android.PrepareForTestWithAndroidBuildComponents,
 android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
  ctx.RegisterModuleType("cc_fuzz", LibFuzzFactory)
  ctx.RegisterModuleType("cc_test", TestFactory)
  ctx.RegisterModuleType("cc_test_host", TestHostFactory)
  ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
  ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)

  RegisterLlndkLibraryTxtType(ctx)
 }),
 android.PrepareForTestWithBuildFlag("RELEASE_SOONG_SANITIZER_VARIANT_ON_DEMAND", "true"),
 android.PrepareForTestWithBuildFlag("RELEASE_SOONG_COV_VARIANT_ON_DEMAND", "true"),
 android.PrepareForTestWithBuildFlag("RELEASE_SOONG_SDK_VARIANT_ON_DEMAND", "true"),
 android.PrepareForTestWithBuildFlag("RELEASE_SOONG_LINK_VARIANT_ON_DEMAND", "true"),
 android.PrepareForTestWithBuildFlag("RELEASE_SOONG_VERSION_VARIANT_ON_DEMAND", "true"),
)

// Preparer that will define default cc modules, e.g. standard prebuilt modules.
var PrepareForTestWithCcDefaultModules = android.GroupFixturePreparers(
 PrepareForTestWithCcBuildComponents,

 // Additional files needed in tests that disallow non-existent source.
 android.MockFS{
  "defaults/cc/common/libc.map.txt":                   nil,
  "defaults/cc/common/libdl.map.txt":                  nil,
  "defaults/cc/common/libft2.map.txt":                 nil,
  "defaults/cc/common/libm.map.txt":                   nil,
  "defaults/cc/common/ndk_libc++_shared_include_dirs": nil,
  "defaults/cc/common/crtbegin_so.c":                  nil,
  "defaults/cc/common/crtbegin.c":                     nil,
  "defaults/cc/common/crtend_so.c":                    nil,
  "defaults/cc/common/crtend.c":                       nil,
  "defaults/cc/common/crtbrand.c":                     nil,
  "external/compiler-rt/lib/cfi/cfi_blocklist.txt":    nil,

  "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil,
  "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a":   nil,
  "defaults/cc/common/libclang_rt.ubsan_minimal.x86_64.a":        nil,
  "defaults/cc/common/libclang_rt.ubsan_minimal.x86.a":           nil,
 }.AddToFixture(),

 // Place the default cc test modules that are common to all platforms in a location that will not
 // conflict with default test modules defined by other packages.
 android.FixtureAddTextFile(DefaultCcCommonTestModulesDir+"Android.bp", commonDefaultModules()),
 // Disable linux bionic by default.
 android.FixtureAddTextFile(linuxBionicDefaultsPath, withoutLinuxBionic()),
)

// Prepare a fixture to use all cc module types, mutators and singletons fully.
//
// This should only be used by tests that want to run with as much of the build enabled as possible.
var PrepareForIntegrationTestWithCc = android.GroupFixturePreparers(
 android.PrepareForIntegrationTestWithAndroid,
 genrule.PrepareForIntegrationTestWithGenrule,
 PrepareForTestWithCcDefaultModules,
)

// The preparer to include if running a cc related test for windows.
var PrepareForTestOnWindows = android.GroupFixturePreparers(
 // Place the default cc test modules for windows platforms in a location that will not conflict
 // with default test modules defined by other packages.
 android.FixtureAddTextFile("defaults/cc/windows/Android.bp", withWindowsModules()),
)

// The preparer to include if running a cc related test for linux bionic.
var PrepareForTestOnLinuxBionic = android.GroupFixturePreparers(
 // Enable linux bionic
 //
 // Can be used after PrepareForTestWithCcDefaultModules to override its default behavior of
 // disabling linux bionic, hence why this uses FixtureOverrideTextFile.
 android.FixtureOverrideTextFile(linuxBionicDefaultsPath, withLinuxBionic()),
)

// PrepareForTestWithHostMusl sets the host configuration to musl libc instead of glibc.  It also disables the test
// on mac, which doesn't support musl libc, and adds musl modules.
var PrepareForTestWithHostMusl = android.GroupFixturePreparers(
 android.FixtureModifyConfig(android.ModifyTestConfigForMusl),
 android.PrepareForSkipTestOnMac,
 android.FixtureAddTextFile("external/musl/Android.bp", `
  cc_defaults {
   name: "libc_musl_crt_defaults",
   host_supported: true,
   device_supported: false,
  }

  cc_object {
   name: "libc_musl_crtbegin_so",
   defaults: ["libc_musl_crt_defaults"],
  }

  cc_object {
   name: "libc_musl_crtend_so",
   defaults: ["libc_musl_crt_defaults"],
  }

  cc_object {
   name: "libc_musl_crtbegin_dynamic",
   defaults: ["libc_musl_crt_defaults"],
  }

  cc_object {
   name: "libc_musl_crtbegin_static",
   defaults: ["libc_musl_crt_defaults"],
  }

  cc_object {
   name: "libc_musl_crtend",
   defaults: ["libc_musl_crt_defaults"],
  }
 `),
)

// PrepareForTestWithFdoProfile registers module types to test with fdo_profile
var PrepareForTestWithFdoProfile = android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
 ctx.RegisterModuleType("soong_namespace", android.NamespaceFactory)
 ctx.RegisterModuleType("fdo_profile", FdoProfileFactory)
})

// TestConfig is the legacy way of creating a test Config for testing cc modules.
//
// See testCc for an explanation as to how to stop using this deprecated method.
//
// deprecated
func TestConfig(buildDir string, os android.OsType, env map[string]string,
 bp string, fs map[string][]byte) android.Config {

 // add some modules that are required by the compiler and/or linker
 bp = bp + GatherRequiredDepsForTest(os)

 mockFS := map[string][]byte{}

 GatherRequiredFilesForTest(mockFS)

 for k, v := range fs {
  mockFS[k] = v
 }

 return android.TestArchConfig(buildDir, env, bp, mockFS)
}

// CreateTestContext is the legacy way of creating a TestContext for testing cc modules.
//
// See testCc for an explanation as to how to stop using this deprecated method.
//
// deprecated
func CreateTestContext(config android.Config) *android.TestContext {
 ctx := android.NewTestArchContext(config)
 genrule.RegisterGenruleBuildComponents(ctx)
 ctx.RegisterModuleType("cc_fuzz", LibFuzzFactory)
 ctx.RegisterModuleType("cc_test", TestFactory)
 ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
 ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)

 RegisterLlndkLibraryTxtType(ctx)

 ctx.PrePartialMutators(android.RegisterDefaultsPreArchMutators)
 android.RegisterPrebuiltMutators(ctx)
 RegisterRequiredBuildComponentsForTest(ctx)

 return ctx
}

func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool, fake bool) {
 t.Helper()
 mod := ctx.ModuleForTests(t, moduleName, variant)
 outputFiles := mod.OutputFiles(ctx, t, "")
 if len(outputFiles) != 1 {
  t.Errorf("%q must have single output\n", moduleName)
  return
 }
 snapshotPath := filepath.Join(subDir, snapshotFilename)

 if include {
  out := singleton.Output(snapshotPath)
  if fake {
   if out.Rule == nil {
    t.Errorf("Missing rule for module %q output file %q", moduleName, outputFiles[0])
   }
  } else {
   if out.Input.String() != outputFiles[0].String() {
    t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0])
   }
  }
 } else {
  out := singleton.MaybeOutput(snapshotPath)
  if out.Rule != nil {
   t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0])
  }
 }
}

func CheckSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
 t.Helper()
 checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, false)
}

func CheckSnapshotExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
 t.Helper()
 checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false, false)
}

func CheckSnapshotRule(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
 t.Helper()
 checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, true)
}

func GetOutputPaths(t *testing.T, ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) {
 t.Helper()
 for _, moduleName := range moduleNames {
  module := ctx.ModuleForTests(t, moduleName, variant).Module().(*Module)
  output := module.outputFile.Path().RelativeToTop()
  paths = append(paths, output)
 }
 return paths
}

[Dauer der Verarbeitung: 0.22 Sekunden, vorverarbeitet 2026-06-28]