Merge "Add jni support to java_fuzz_host" am: 4e70b7586a
Original change: https://android-review.googlesource.com/c/platform/build/soong/+/2045705 Change-Id: Ia5971f11a607df9d214469a133db41d0c7c0d83d Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
5b63f52025
6 changed files with 173 additions and 20 deletions
1
cc/cc.go
1
cc/cc.go
|
@ -746,6 +746,7 @@ var (
|
||||||
runtimeDepTag = installDependencyTag{name: "runtime lib"}
|
runtimeDepTag = installDependencyTag{name: "runtime lib"}
|
||||||
testPerSrcDepTag = dependencyTag{name: "test_per_src"}
|
testPerSrcDepTag = dependencyTag{name: "test_per_src"}
|
||||||
stubImplDepTag = dependencyTag{name: "stub_impl"}
|
stubImplDepTag = dependencyTag{name: "stub_impl"}
|
||||||
|
JniFuzzLibTag = dependencyTag{name: "jni_fuzz_lib_tag"}
|
||||||
)
|
)
|
||||||
|
|
||||||
func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
|
func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
|
||||||
|
|
|
@ -969,6 +969,22 @@ func sanitizerDepsMutator(t SanitizerType) func(android.TopDownMutatorContext) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
|
} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
|
||||||
|
// If it's a Java module with native dependencies through jni,
|
||||||
|
// set the sanitizer for them
|
||||||
|
if jniSanitizeable, ok := mctx.Module().(JniSanitizeable); ok {
|
||||||
|
if jniSanitizeable.IsSanitizerEnabledForJni(mctx, t.name()) {
|
||||||
|
mctx.VisitDirectDeps(func(child android.Module) {
|
||||||
|
if c, ok := child.(PlatformSanitizeable); ok &&
|
||||||
|
mctx.OtherModuleDependencyTag(child) == JniFuzzLibTag &&
|
||||||
|
c.SanitizePropDefined() &&
|
||||||
|
!c.SanitizeNever() &&
|
||||||
|
!c.IsSanitizerExplicitlyDisabled(t) {
|
||||||
|
c.SetSanitizeDep(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If an APEX module includes a lib which is enabled for a sanitizer T, then
|
// If an APEX module includes a lib which is enabled for a sanitizer T, then
|
||||||
// the APEX module is also enabled for the same sanitizer type.
|
// the APEX module is also enabled for the same sanitizer type.
|
||||||
mctx.VisitDirectDeps(func(child android.Module) {
|
mctx.VisitDirectDeps(func(child android.Module) {
|
||||||
|
@ -1280,6 +1296,11 @@ type Sanitizeable interface {
|
||||||
AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string)
|
AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JniSanitizeable interface {
|
||||||
|
android.Module
|
||||||
|
IsSanitizerEnabledForJni(ctx android.BaseModuleContext, sanitizerName string) bool
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Module) MinimalRuntimeDep() bool {
|
func (c *Module) MinimalRuntimeDep() bool {
|
||||||
return c.sanitize.Properties.MinimalRuntimeDep
|
return c.sanitize.Properties.MinimalRuntimeDep
|
||||||
}
|
}
|
||||||
|
@ -1407,7 +1428,7 @@ func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) {
|
||||||
}
|
}
|
||||||
c.SetSanitizeDep(false)
|
c.SetSanitizeDep(false)
|
||||||
} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) {
|
} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) {
|
||||||
// APEX modules fall here
|
// APEX and Java fuzz modules fall here
|
||||||
sanitizeable.AddSanitizerDependencies(mctx, t.name())
|
sanitizeable.AddSanitizerDependencies(mctx, t.name())
|
||||||
mctx.CreateVariations(t.variationName())
|
mctx.CreateVariations(t.variationName())
|
||||||
} else if c, ok := mctx.Module().(*Module); ok {
|
} else if c, ok := mctx.Module().(*Module); ok {
|
||||||
|
|
|
@ -82,6 +82,9 @@ type FuzzConfig struct {
|
||||||
Hwasan_options []string `json:"hwasan_options,omitempty"`
|
Hwasan_options []string `json:"hwasan_options,omitempty"`
|
||||||
// Additional options to be passed to HWASAN when running on host in Haiku.
|
// Additional options to be passed to HWASAN when running on host in Haiku.
|
||||||
Asan_options []string `json:"asan_options,omitempty"`
|
Asan_options []string `json:"asan_options,omitempty"`
|
||||||
|
// If there's a Java fuzzer with JNI, a different version of Jazzer would
|
||||||
|
// need to be added to the fuzzer package than one without JNI
|
||||||
|
IsJni *bool `json:"is_jni,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FuzzProperties struct {
|
type FuzzProperties struct {
|
||||||
|
|
|
@ -132,6 +132,16 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
|
||||||
return entriesList
|
return entriesList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *JavaFuzzLibrary) AndroidMkEntries() []android.AndroidMkEntries {
|
||||||
|
entriesList := j.Library.AndroidMkEntries()
|
||||||
|
entries := &entriesList[0]
|
||||||
|
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
||||||
|
entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", "null-suite")
|
||||||
|
androidMkWriteTestData(j.jniFilePaths, entries)
|
||||||
|
})
|
||||||
|
return entriesList
|
||||||
|
}
|
||||||
|
|
||||||
// Called for modules that are a component of a test suite.
|
// Called for modules that are a component of a test suite.
|
||||||
func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string, perTestcaseDirectory bool) {
|
func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string, perTestcaseDirectory bool) {
|
||||||
entries.SetString("LOCAL_MODULE_TAGS", "tests")
|
entries.SetString("LOCAL_MODULE_TAGS", "tests")
|
||||||
|
|
113
java/fuzz.go
113
java/fuzz.go
|
@ -15,14 +15,25 @@
|
||||||
package java
|
package java
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/google/blueprint/proptools"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/blueprint"
|
||||||
|
"github.com/google/blueprint/proptools"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
|
"android/soong/cc"
|
||||||
"android/soong/fuzz"
|
"android/soong/fuzz"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type jniProperties struct {
|
||||||
|
// list of jni libs
|
||||||
|
Jni_libs []string
|
||||||
|
|
||||||
|
// sanitization
|
||||||
|
Sanitizers []string
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterJavaFuzzBuildComponents(android.InitRegistrationContext)
|
RegisterJavaFuzzBuildComponents(android.InitRegistrationContext)
|
||||||
}
|
}
|
||||||
|
@ -35,11 +46,60 @@ func RegisterJavaFuzzBuildComponents(ctx android.RegistrationContext) {
|
||||||
type JavaFuzzLibrary struct {
|
type JavaFuzzLibrary struct {
|
||||||
Library
|
Library
|
||||||
fuzzPackagedModule fuzz.FuzzPackagedModule
|
fuzzPackagedModule fuzz.FuzzPackagedModule
|
||||||
|
jniProperties jniProperties
|
||||||
|
jniFilePaths android.Paths
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSanitizerEnabled implemented to make JavaFuzzLibrary implement
|
||||||
|
// cc.Sanitizeable
|
||||||
|
func (j *JavaFuzzLibrary) IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool {
|
||||||
|
for _, s := range j.jniProperties.Sanitizers {
|
||||||
|
if sanitizerName == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSanitizerEnabledForJni implemented to make JavaFuzzLibrary implement
|
||||||
|
// cc.JniSanitizeable. It returns a bool for whether a cc dependency should be
|
||||||
|
// sanitized for the given sanitizer or not.
|
||||||
|
func (j *JavaFuzzLibrary) IsSanitizerEnabledForJni(ctx android.BaseModuleContext, sanitizerName string) bool {
|
||||||
|
return j.IsSanitizerEnabled(ctx, sanitizerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableSanitizer implemented to make JavaFuzzLibrary implement
|
||||||
|
// cc.Sanitizeable
|
||||||
|
func (j *JavaFuzzLibrary) EnableSanitizer(sanitizerName string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSanitizerDependencies implemented to make JavaFuzzLibrary implement
|
||||||
|
// cc.Sanitizeable
|
||||||
|
func (j *JavaFuzzLibrary) AddSanitizerDependencies(mctx android.BottomUpMutatorContext, sanitizerName string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// To verify that JavaFuzzLibrary implements cc.Sanitizeable
|
||||||
|
var _ cc.Sanitizeable = (*JavaFuzzLibrary)(nil)
|
||||||
|
|
||||||
|
func (j *JavaFuzzLibrary) DepsMutator(mctx android.BottomUpMutatorContext) {
|
||||||
|
if len(j.jniProperties.Jni_libs) > 0 {
|
||||||
|
if j.fuzzPackagedModule.FuzzProperties.Fuzz_config == nil {
|
||||||
|
config := &fuzz.FuzzConfig{}
|
||||||
|
j.fuzzPackagedModule.FuzzProperties.Fuzz_config = config
|
||||||
|
}
|
||||||
|
// this will be used by the ingestion pipeline to determine the version
|
||||||
|
// of jazzer to add to the fuzzer package
|
||||||
|
j.fuzzPackagedModule.FuzzProperties.Fuzz_config.IsJni = proptools.BoolPtr(true)
|
||||||
|
|
||||||
|
for _, target := range mctx.MultiTargets() {
|
||||||
|
sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
|
||||||
|
mctx.AddFarVariationDependencies(sharedLibVariations, cc.JniFuzzLibTag, j.jniProperties.Jni_libs...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j.Library.DepsMutator(mctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *JavaFuzzLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
func (j *JavaFuzzLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
j.Library.GenerateAndroidBuildActions(ctx)
|
|
||||||
|
|
||||||
if j.fuzzPackagedModule.FuzzProperties.Corpus != nil {
|
if j.fuzzPackagedModule.FuzzProperties.Corpus != nil {
|
||||||
j.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Corpus)
|
j.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Corpus)
|
||||||
}
|
}
|
||||||
|
@ -55,6 +115,23 @@ func (j *JavaFuzzLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)
|
||||||
android.WriteFileRule(ctx, configPath, j.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
|
android.WriteFileRule(ctx, configPath, j.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
|
||||||
j.fuzzPackagedModule.Config = configPath
|
j.fuzzPackagedModule.Config = configPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.VisitDirectDepsWithTag(cc.JniFuzzLibTag, func(dep android.Module) {
|
||||||
|
sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo)
|
||||||
|
if sharedLibInfo.SharedLibrary != nil {
|
||||||
|
libPath := android.PathForModuleOut(ctx, sharedLibInfo.SharedLibrary.Base())
|
||||||
|
ctx.Build(pctx, android.BuildParams{
|
||||||
|
Rule: android.Cp,
|
||||||
|
Input: sharedLibInfo.SharedLibrary,
|
||||||
|
Output: libPath,
|
||||||
|
})
|
||||||
|
j.jniFilePaths = append(j.jniFilePaths, libPath)
|
||||||
|
} else {
|
||||||
|
ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
j.Library.GenerateAndroidBuildActions(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// java_fuzz builds and links sources into a `.jar` file for the host.
|
// java_fuzz builds and links sources into a `.jar` file for the host.
|
||||||
|
@ -65,7 +142,8 @@ func FuzzFactory() android.Module {
|
||||||
module := &JavaFuzzLibrary{}
|
module := &JavaFuzzLibrary{}
|
||||||
|
|
||||||
module.addHostProperties()
|
module.addHostProperties()
|
||||||
module.Module.properties.Installable = proptools.BoolPtr(false)
|
module.AddProperties(&module.jniProperties)
|
||||||
|
module.Module.properties.Installable = proptools.BoolPtr(true)
|
||||||
module.AddProperties(&module.fuzzPackagedModule.FuzzProperties)
|
module.AddProperties(&module.fuzzPackagedModule.FuzzProperties)
|
||||||
|
|
||||||
// java_fuzz packaging rules collide when both linux_glibc and linux_bionic are enabled, disable the linux_bionic variants.
|
// java_fuzz packaging rules collide when both linux_glibc and linux_bionic are enabled, disable the linux_bionic variants.
|
||||||
|
@ -83,7 +161,7 @@ func FuzzFactory() android.Module {
|
||||||
|
|
||||||
module.initModuleAndImport(module)
|
module.initModuleAndImport(module)
|
||||||
android.InitSdkAwareModule(module)
|
android.InitSdkAwareModule(module)
|
||||||
InitJavaModule(module, android.HostSupported)
|
InitJavaModuleMultiTargets(module, android.HostSupported)
|
||||||
return module
|
return module
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,26 +184,26 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
|
||||||
|
|
||||||
ctx.VisitAllModules(func(module android.Module) {
|
ctx.VisitAllModules(func(module android.Module) {
|
||||||
// Discard non-fuzz targets.
|
// Discard non-fuzz targets.
|
||||||
javaModule, ok := module.(*JavaFuzzLibrary)
|
javaFuzzModule, ok := module.(*JavaFuzzLibrary)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fuzzModuleValidator := fuzz.FuzzModule{
|
fuzzModuleValidator := fuzz.FuzzModule{
|
||||||
javaModule.ModuleBase,
|
javaFuzzModule.ModuleBase,
|
||||||
javaModule.DefaultableModuleBase,
|
javaFuzzModule.DefaultableModuleBase,
|
||||||
javaModule.ApexModuleBase,
|
javaFuzzModule.ApexModuleBase,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok := fuzz.IsValid(fuzzModuleValidator); !ok || *javaModule.Module.properties.Installable {
|
if ok := fuzz.IsValid(fuzzModuleValidator); !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hostOrTargetString := "target"
|
hostOrTargetString := "target"
|
||||||
if javaModule.Host() {
|
if javaFuzzModule.Host() {
|
||||||
hostOrTargetString = "host"
|
hostOrTargetString = "host"
|
||||||
}
|
}
|
||||||
archString := javaModule.Arch().ArchType.String()
|
archString := javaFuzzModule.Arch().ArchType.String()
|
||||||
|
|
||||||
archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
|
archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
|
||||||
archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
|
archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
|
||||||
|
@ -134,12 +212,17 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
|
||||||
builder := android.NewRuleBuilder(pctx, ctx)
|
builder := android.NewRuleBuilder(pctx, ctx)
|
||||||
|
|
||||||
// Package the artifacts (data, corpus, config and dictionary into a zipfile.
|
// Package the artifacts (data, corpus, config and dictionary into a zipfile.
|
||||||
files = s.PackageArtifacts(ctx, module, javaModule.fuzzPackagedModule, archDir, builder)
|
files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder)
|
||||||
|
|
||||||
// Add .jar
|
// Add .jar
|
||||||
files = append(files, fuzz.FileToZip{javaModule.outputFile, ""})
|
files = append(files, fuzz.FileToZip{javaFuzzModule.outputFile, ""})
|
||||||
|
|
||||||
archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaModule.fuzzPackagedModule, files, builder, archDir, archString, "host", archOs, archDirs)
|
// Add jni .so files
|
||||||
|
for _, fPath := range javaFuzzModule.jniFilePaths {
|
||||||
|
files = append(files, fuzz.FileToZip{fPath, ""})
|
||||||
|
}
|
||||||
|
|
||||||
|
archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaFuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,17 @@
|
||||||
package java
|
package java
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"android/soong/android"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"android/soong/android"
|
||||||
|
"android/soong/cc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var prepForJavaFuzzTest = android.GroupFixturePreparers(
|
var prepForJavaFuzzTest = android.GroupFixturePreparers(
|
||||||
PrepareForTestWithJavaDefaultModules,
|
PrepareForTestWithJavaDefaultModules,
|
||||||
|
cc.PrepareForTestWithCcBuildComponents,
|
||||||
android.FixtureRegisterWithContext(RegisterJavaFuzzBuildComponents),
|
android.FixtureRegisterWithContext(RegisterJavaFuzzBuildComponents),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,6 +36,13 @@ func TestJavaFuzz(t *testing.T) {
|
||||||
srcs: ["a.java"],
|
srcs: ["a.java"],
|
||||||
libs: ["bar"],
|
libs: ["bar"],
|
||||||
static_libs: ["baz"],
|
static_libs: ["baz"],
|
||||||
|
jni_libs: [
|
||||||
|
"libjni",
|
||||||
|
],
|
||||||
|
sanitizers: [
|
||||||
|
"address",
|
||||||
|
"fuzzer",
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
java_library_host {
|
java_library_host {
|
||||||
|
@ -42,11 +53,21 @@ func TestJavaFuzz(t *testing.T) {
|
||||||
java_library_host {
|
java_library_host {
|
||||||
name: "baz",
|
name: "baz",
|
||||||
srcs: ["c.java"],
|
srcs: ["c.java"],
|
||||||
}`)
|
}
|
||||||
|
|
||||||
|
cc_library_shared {
|
||||||
|
name: "libjni",
|
||||||
|
host_supported: true,
|
||||||
|
device_supported: false,
|
||||||
|
stl: "none",
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
osCommonTarget := result.Config.BuildOSCommonTarget.String()
|
osCommonTarget := result.Config.BuildOSCommonTarget.String()
|
||||||
javac := result.ModuleForTests("foo", osCommonTarget).Rule("javac")
|
|
||||||
combineJar := result.ModuleForTests("foo", osCommonTarget).Description("for javac")
|
osCommonTargetWithSan := osCommonTarget + "_asan" + "_fuzzer"
|
||||||
|
javac := result.ModuleForTests("foo", osCommonTargetWithSan).Rule("javac")
|
||||||
|
combineJar := result.ModuleForTests("foo", osCommonTargetWithSan).Description("for javac")
|
||||||
|
|
||||||
if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
|
if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
|
||||||
t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
|
t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
|
||||||
|
@ -62,4 +83,18 @@ func TestJavaFuzz(t *testing.T) {
|
||||||
if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
|
if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
|
||||||
t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
|
t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx := result.TestContext
|
||||||
|
foo := ctx.ModuleForTests("foo", osCommonTargetWithSan).Module().(*JavaFuzzLibrary)
|
||||||
|
|
||||||
|
expected := "libjni.so"
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
expected = "libjni.dylib"
|
||||||
|
}
|
||||||
|
|
||||||
|
fooJniFilePaths := foo.jniFilePaths
|
||||||
|
if len(fooJniFilePaths) != 1 || fooJniFilePaths[0].Rel() != expected {
|
||||||
|
t.Errorf(`expected foo test data relative path [%q], got %q`,
|
||||||
|
expected, fooJniFilePaths.Strings())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue