package spdxexp

import (
	"fmt"
	"testing"
)

type satisfiesBenchmarkScenario struct {
	name           string
	testExpression string
}

var satisfiesBenchmarkScenarios = []satisfiesBenchmarkScenario{
	// Scenario order is used as-is in the summary table.
	{"MIT--exact", "MIT"},
	{"mit--caseinsensitive", "mit"},
	{"mit--extra-space", " MIT  "},
	{"Apache-2.0--active-early", "Apache-2.0"},
	{"Zed--active-end", "Zed"},
	{"MIT AND Apache-2.0--complex", "MIT AND Apache-2.0"},
	{"MIT AND Apache-2.0 OR Zed--complex", "MIT AND Apache-2.0 OR Zed"},
	{"BSD-2-Clause-FreeBSD--deprecated", "BSD-2-Clause-FreeBSD"},
	{"GPL-2.0-or-later--range", "GPL-2.0-or-later"},
	{"Apache-1.0+--plus-range", "Apache-1.0+"},
	{"LicenseRef-scancode-adobe-postscript", "LicenseRef-scancode-adobe-postscript"},
	{"DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2", "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2"},
}

func BenchmarkSatisfies(b *testing.B) {
	for _, scenario := range satisfiesBenchmarkScenarios {
		scenario := scenario
		b.Run(scenario.name, func(b *testing.B) {
			benchmarkSatisfiesScenario(b, scenario.testExpression)
		})
	}
}

func benchmarkSatisfiesScenario(b *testing.B, expression string) {
	b.ReportAllocs()
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		_, err := Satisfies(expression, allowList())
		if err != nil {
			b.Fatalf("Satisfies(%q, allowList) error: %v", expression, err)
		}
	}
}

func computeSatisfiesBenchmarkTableRows(repeats int) []benchmarkTableRow {
	rows := make([]benchmarkTableRow, 0, len(satisfiesBenchmarkScenarios))

	for _, scenario := range satisfiesBenchmarkScenarios {
		scenario := scenario
		avg := runBenchmarkNsAvg(repeats, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				_, err := Satisfies(scenario.testExpression, allowList())
				if err != nil {
					panic(fmt.Sprintf("Satisfies scenario %q error: %v", scenario.name, err))
				}
			}
		})
		rows = append(rows, benchmarkTableRow{label: scenario.name, nsOpAvg: avg})
	}

	return rows
}

func allowList() []string {
	// common list of permissive licenses to simulate a realistic use case for Satisfies
	return []string{
		"0BSD",
		"3D-Slicer-1.0",
		"AAL",
		"Abstyles",
		"AdaCore-doc",
		"Adobe-2006",
		"Adobe-Display-PostScript",
		"Adobe-Glyph",
		"Adobe-Utopia",
		"ADSL",
		"AFL-1.1",
		"AFL-1.2",
		"AFL-2.0",
		"AFL-2.1",
		"AFL-3.0",
		"Afmparse",
		"AMD-newlib",
		"AMDPLPA",
		"AML",
		"AML-glslang",
		"AMPAS",
		"ANTLR-PD",
		"ANTLR-PD-fallback",
		"Apache-1.0",
		"Apache-1.1",
		"Apache-2.0",
		"APAFML",
		"App-s2p",
		"Aspell-RU",
		"Baekmuk",
		"Bahyph",
		"Barr",
		"bcrypt-Solar-Designer",
		"Beerware",
		"Bitstream-Charter",
		"Bitstream-Vera",
		"blessing",
		"BlueOak-1.0.0",
		"Boehm-GC",
		"Boehm-GC-without-fee",
		"Borceux",
		"Brian-Gladman-2-Clause",
		"Brian-Gladman-3-Clause",
		"BSD-1-Clause",
		"BSD-2-Clause",
		"BSD-2-Clause-Darwin",
		"BSD-2-Clause-first-lines",
		"BSD-2-Clause-Patent",
		"BSD-2-Clause-pkgconf-disclaimer",
		"BSD-2-Clause-Views",
		"BSD-3-Clause",
		"BSD-3-Clause-acpica",
		"BSD-3-Clause-Attribution",
		"BSD-3-Clause-Clear",
		"BSD-3-Clause-flex",
		"BSD-3-Clause-HP",
		"BSD-3-Clause-LBNL",
		"BSD-3-Clause-Modification",
		"BSD-3-Clause-Open-MPI",
		"BSD-3-Clause-Sun",
		"BSD-4-Clause",
		"BSD-4-Clause-Shortened",
		"BSD-4-Clause-UC",
		"BSD-4.3RENO",
		"BSD-4.3TAHOE",
		"BSD-Advertising-Acknowledgement",
		"BSD-Attribution-HPND-disclaimer",
		"BSD-Inferno-Nettverk",
		"BSD-Source-beginning-file",
		"BSD-Source-Code",
		"BSD-Systemics",
		"BSD-Systemics-W3Works",
		"BSL-1.0",
		"bzip2-1.0.6",
		"Caldera-no-preamble",
		"Catharon",
		"CC-BY-1.0",
		"CC-BY-2.0",
		"CC-BY-2.5",
		"CC-BY-2.5-AU",
		"CC-BY-3.0",
		"CC-BY-3.0-AT",
		"CC-BY-3.0-AU",
		"CC-BY-3.0-DE",
		"CC-BY-3.0-IGO",
		"CC-BY-3.0-NL",
		"CC-BY-3.0-US",
		"CC-BY-4.0",
		"CC-PDDC",
		"CC-PDM-1.0",
		"CC0-1.0",
		"CDLA-Permissive-1.0",
		"CDLA-Permissive-2.0",
		"CECILL-B",
		"CERN-OHL-1.1",
		"CERN-OHL-1.2",
		"CERN-OHL-P-2.0",
		"CFITSIO",
		"check-cvs",
		"checkmk",
		"Clips",
		"CMU-Mach",
		"CMU-Mach-nodoc",
		"CNRI-Jython",
		"CNRI-Python",
		"CNRI-Python-GPL-Compatible",
		"COIL-1.0",
		"Community-Spec-1.0",
		"Condor-1.1",
		"Cornell-Lossless-JPEG",
		"Cronyx",
		"Crossword",
		"CryptoSwift",
		"CrystalStacker",
		"Cube",
		"curl",
		"cve-tou",
		"DEC-3-Clause",
		"diffmark",
		"DL-DE-BY-2.0",
		"DL-DE-ZERO-2.0",
		"DOC",
		"DocBook-DTD",
		"DocBook-Schema",
		"DocBook-Stylesheet",
		"DocBook-XML",
		"Dotseqn",
		"DRL-1.0",
		"DRL-1.1",
		"DSDP",
		"dtoa",
		"dvipdfm",
		"ECL-1.0",
		"ECL-2.0",
		"EFL-1.0",
		"EFL-2.0",
		"eGenix",
		"Entessa",
		"EPICS",
		"etalab-2.0",
		"EUDatagrid",
		"Fair",
		"FBM",
		"Ferguson-Twofish",
		"FreeBSD-DOC",
		"FSFAP",
		"FSFAP-no-warranty-disclaimer",
		"FSFUL",
		"FSFULLR",
		"FSFULLRSD",
		"FSFULLRWD",
		"FTL",
		"Furuseth",
		"fwlw",
		"Game-Programming-Gems",
		"GD",
		"generic-xts",
		"Giftware",
		"Glulxe",
		"GLWTPL",
		"Graphics-Gems",
		"gtkbook",
		"Gutmann",
		"HaskellReport",
		"HDF5",
		"hdparm",
		"HIDAPI",
		"HP-1986",
		"HP-1989",
		"HPND",
		"HPND-DEC",
		"HPND-doc",
		"HPND-doc-sell",
		"HPND-export-US-modify",
		"HPND-export2-US",
		"HPND-Fenneberg-Livingston",
		"HPND-INRIA-IMAG",
		"HPND-Intel",
		"HPND-Kevlin-Henney",
		"HPND-Markus-Kuhn",
		"HPND-merchantability-variant",
		"HPND-MIT-disclaimer",
		"HPND-Netrek",
		"HPND-Pbmplus",
		"HPND-sell-MIT-disclaimer-xserver",
		"HPND-sell-regexpr",
		"HPND-sell-variant",
		"HPND-sell-variant-MIT-disclaimer",
		"HPND-sell-variant-MIT-disclaimer-rev",
		"HPND-UC",
		"HTMLTIDY",
		"IBM-pibs",
		"ICU",
		"IEC-Code-Components-EULA",
		"IJG",
		"IJG-short",
		"ImageMagick",
		"iMatix",
		"Info-ZIP",
		"Inner-Net-2.0",
		"InnoSetup",
		"Intel",
		"Intel-ACPI",
		"ISC",
		"ISC-Veillard",
		"Jam",
		"JasPer-2.0",
		"jove",
		"JPNIC",
		"JSON",
		"Kastrup",
		"Kazlib",
		"Knuth-CTAN",
		"Latex2e",
		"Latex2e-translated-notice",
		"Leptonica",
		"Libpng",
		"libpng-1.6.35",
		"libpng-2.0",
		"libselinux-1.0",
		"libtiff",
		"libutil-David-Nugent",
		"Linux-OpenIB",
		"LOOP",
		"LPD-document",
		"lsof",
		"Lucida-Bitmap-Fonts",
		"LZMA-SDK-9.11-to-9.20",
		"LZMA-SDK-9.22",
		"Mackerras-3-Clause",
		"Mackerras-3-Clause-acknowledgment",
		"magaz",
		"mailprio",
		"man2html",
		"Martin-Birgmeier",
		"McPhee-slideshow",
		"metamail",
		"Minpack",
		"MIPS",
		"MirOS",
		"MIT",
		"MIT-0",
		"MIT-advertising",
		"MIT-Click",
		"MIT-CMU",
		"MIT-enna",
		"MIT-feh",
		"MIT-Festival",
		"MIT-Khronos-old",
		"MIT-Modern-Variant",
		"MIT-open-group",
		"MIT-testregex",
		"MIT-Wu",
		"MITNFA",
		"MMIXware",
		"MPEG-SSG",
		"mpi-permissive",
		"mpich2",
		"mplus",
		"MS-LPL",
		"MS-PL",
		"MTLL",
		"MulanPSL-1.0",
		"MulanPSL-2.0",
		"Multics",
		"Mup",
		"NAIST-2003",
		"Naumen",
		"NCBI-PD",
		"NCL",
		"NCSA",
		"NetCDF",
		"Newsletr",
		"ngrep",
		"NICTA-1.0",
		"NIST-PD",
		"NIST-PD-fallback",
		"NIST-Software",
		"NLOD-1.0",
		"NLOD-2.0",
		"NLPL",
		"NRL",
		"NTIA-PD",
		"NTP",
		"NTP-0",
		"O-UDA-1.0",
		"OAR",
		"ODC-By-1.0",
		"OFFIS",
		"OFL-1.0",
		"OFL-1.0-no-RFN",
		"OFL-1.0-RFN",
		"OFL-1.1-no-RFN",
		"OFL-1.1-RFN",
		"OGC-1.0",
		"OGDL-Taiwan-1.0",
		"OGL-Canada-2.0",
		"OGL-UK-1.0",
		"OGL-UK-2.0",
		"OGL-UK-3.0",
		"OLDAP-2.0",
		"OLDAP-2.0.1",
		"OLDAP-2.1",
		"OLDAP-2.2",
		"OLDAP-2.2.1",
		"OLDAP-2.2.2",
		"OLDAP-2.3",
		"OLDAP-2.4",
		"OLDAP-2.5",
		"OLDAP-2.6",
		"OLDAP-2.7",
		"OLDAP-2.8",
		"OLFL-1.3",
		"OML",
		"OpenSSL",
		"OpenSSL-standalone",
		"OpenVision",
		"OPL-UK-3.0",
		"OPUBL-1.0",
		"PADL",
		"PDDL-1.0",
		"PHP-3.0",
		"PHP-3.01",
		"Pixar",
		"pkgconf",
		"Plexus",
		"pnmstitch",
		"PostgreSQL",
		"PSF-2.0",
		"psfrag",
		"psutils",
		"Python-2.0",
		"Python-2.0.1",
		"python-ldap",
		"radvd",
		"Rdisc",
		"RSA-MD",
		"Ruby-pty",
		"SAX-PD",
		"SAX-PD-2.0",
		"Saxpath",
		"SCEA",
		"SchemeReport",
		"Sendmail",
		"Sendmail-Open-Source-1.1",
		"SGI-B-1.1",
		"SGI-B-2.0",
		"SGI-OpenGL",
		"SGP4",
		"SHL-0.5",
		"SHL-0.51",
		"SL",
		"SMLNJ",
		"snprintf",
		"softSurfer",
		"Soundex",
		"Spencer-86",
		"Spencer-94",
		"Spencer-99",
		"ssh-keyscan",
		"SSH-OpenSSH",
		"SSH-short",
		"SSLeay-standalone",
		"Sun-PPP",
		"Sun-PPP-2000",
		"SunPro",
		"SWL",
		"swrule",
		"Symlinks",
		"TCL",
		"TCP-wrappers",
		"TermReadKey",
		"ThirdEye",
		"threeparttable",
		"TPDL",
		"TrustedQSL",
		"TTWL",
		"TTYP0",
		"TU-Berlin-1.0",
		"TU-Berlin-2.0",
		"UCAR",
		"ulem",
		"UMich-Merit",
		"Unicode-3.0",
		"Unicode-DFS-2015",
		"Unicode-DFS-2016",
		"UnixCrypt",
		"Unlicense",
		"Unlicense-libtelnet",
		"Unlicense-libwhirlpool",
		"UPL-1.0",
		"VSL-1.0",
		"W3C",
		"W3C-19980720",
		"W3C-20150513",
		"w3m",
		"Widget-Workshop",
		"Wsuipa",
		"WTFPL",
		"wwl",
		"X11",
		"X11-distribute-modifications-variant",
		"X11-swapped",
		"Xdebug-1.03",
		"Xerox",
		"Xfig",
		"XFree86-1.1",
		"xinetd",
		"xkeyboard-config-Zinoviev",
		"xlock",
		"Xnet",
		"xpp",
		"XSkat",
		"xzoom",
		"Zed",
		"Zeeff",
		"Zend-2.0",
		"Zlib",
		"zlib-acknowledgement",
		"ZPL-1.1",
		"ZPL-2.0",
		"ZPL-2.1",
	}
}
