java-topology/defects/rails/unit/RailsTest.java

709 lines
34 KiB
Java
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package unit;
import java.util.*;
/**
* RailsTest — rails-0001..0018
*
* Proves CWE-407 in Ruby on Rails:
* rails-0001: Preloader::Batch — future_tables Array#include? in loaders.reject O(L×F) per batch
* rails-0002: Callbacks — chain.index(callback) inside skip_callback filters loop O(D×F×C²)
* rails-0003: Enumerable#excluding — elements.include? in reject loop O(N×E)
* rails-0004: Enumerable#in_order_of — series.index in sort_by block O(N log N × S)
* rails-0005: SchemaDumper — constraint_names Array#include? in indexes.reject O(I×C)
* rails-0006: PostgreSQL schema_statements — include_columns Array#include? in reject O(C×I)
* rails-0007: lazy_load_hooks — @run_once[name].include?(block) Array scan per hook O(H×R)
* rails-0008: Enum — value_method_names.include? in pairs.each loop O(E²)
* rails-0009: FilterAttributeHandler — filter_params.include? in each loop O(A×F)
* rails-0010: Encryption::AutoFilteredParams — filter_parameters.include? in each O(A×F)
* rails-0011: TimeZoneConversion — skip_list.include? per column per model O(M×C×S)
* rails-0012: options_for_select — Array(selected).include? in container.map O(N×S)
* rails-0013: CollectionHelpers — Array(current_value).include? in render_collection O(C×V×4)
* rails-0014: ActiveJob::Arguments — symbol_keys.include? in transform_keys loop O(H×S)
* rails-0015: schema_statements — inserting.count(v) in detect loop O(V²) dupe check
* rails-0016: SQLite3Adapter — to_column_names.include? in copy_table_indexes O(I×C×N)
* rails-0017: schema_statements — index.columns.include? in rename_column_indexes O(I×C)
* rails-0018: CollectionAssociation#find_by_scan — ids Array#include? in load_target.select O(T×I)
*
* Run: javac -d . RailsTest.java && java -ea unit.RailsTest
*/
public class RailsTest {
// ── rails-0001: Preloader::Batch future_tables ────────────────────────────
/** SLOW: future_tables as Array — Array#include? per loader per batch */
static long preloaderSlow(int loaders, int futureTables, int batchRounds) {
List<String> futureArr = new ArrayList<>();
for (int i = 0; i < futureTables; i++) futureArr.add("table_" + i);
long ops = 0;
for (int round = 0; round < batchRounds; round++) {
// loaders.reject { |l| future_tables.include?(l.table_name) }
for (int l = 0; l < loaders; l++) {
String table = "table_" + (l % (futureTables * 2));
for (String t : futureArr) { ops++; if (t.equals(table)) break; }
}
}
return ops;
}
/** FAST: future_tables as Set — O(1) include? per loader */
static long preloaderFast(int loaders, int futureTables, int batchRounds) {
Set<String> futureSet = new HashSet<>();
for (int i = 0; i < futureTables; i++) futureSet.add("table_" + i);
long ops = 0;
for (int round = 0; round < batchRounds; round++) {
for (int l = 0; l < loaders; l++) {
String table = "table_" + (l % (futureTables * 2));
ops++; // O(1) set lookup
futureSet.contains(table);
}
}
return ops;
}
// ── rails-0002: Callbacks chain.index ────────────────────────────────────
/** SLOW: chain.index(callback) — O(C) scan inside filters.each across descendants */
static long callbacksSlow(int descendants, int filters, int chainLength) {
long ops = 0;
for (int d = 0; d < descendants; d++) {
List<Integer> chain = new ArrayList<>();
for (int i = 0; i < chainLength; i++) chain.add(i);
for (int f = 0; f < filters; f++) {
// chain.find { matches? } — skip, then chain.index — O(C)
Integer callback = f < chainLength ? f : null;
if (callback != null) {
// chain.index(callback) — O(C) scan
for (int i = 0; i < chain.size(); i++) { ops++; if (chain.get(i).equals(callback)) break; }
}
}
}
return ops;
}
/** FAST: position_map built once — O(1) lookup per filter */
static long callbacksFast(int descendants, int filters, int chainLength) {
long ops = 0;
for (int d = 0; d < descendants; d++) {
List<Integer> chain = new ArrayList<>();
Map<Integer, Integer> posMap = new HashMap<>();
for (int i = 0; i < chainLength; i++) { chain.add(i); posMap.put(i, i); }
for (int f = 0; f < filters; f++) {
Integer callback = f < chainLength ? f : null;
if (callback != null) {
ops++; // O(1) map lookup
posMap.get(callback);
}
}
}
return ops;
}
// ── rails-0003: Enumerable#excluding ─────────────────────────────────────
/** SLOW: elements.include? inside reject — O(N×E) */
static long excludingSlow(int receiverSize, int excludeSize) {
List<Integer> receiver = new ArrayList<>();
List<Integer> elements = new ArrayList<>();
for (int i = 0; i < receiverSize; i++) receiver.add(i);
for (int i = 0; i < excludeSize; i++) elements.add(i);
long ops = 0;
for (int r : receiver) {
for (int e : elements) { ops++; if (e == r) break; }
}
return ops;
}
/** FAST: exclusions as Set — O(1) per element */
static long excludingFast(int receiverSize, int excludeSize) {
Set<Integer> exclusions = new HashSet<>();
for (int i = 0; i < excludeSize; i++) exclusions.add(i);
long ops = 0;
for (int i = 0; i < receiverSize; i++) { ops++; exclusions.contains(i); }
return ops;
}
// ── rails-0004: Enumerable#in_order_of ───────────────────────────────────
/** SLOW: series.index inside sort comparator — O(N log N × S) */
static long inOrderOfSlow(int collectionSize, int seriesSize) {
List<Integer> collection = new ArrayList<>();
List<Integer> series = new ArrayList<>();
for (int i = 0; i < collectionSize; i++) collection.add(i % seriesSize);
for (int i = 0; i < seriesSize; i++) series.add(i);
long ops = 0;
// Simulate sort_by with series.index (O(S)) called in comparator
// In Java: each comparison calls indexOf (total ~N log N comparisons)
for (int v : collection) {
// series.index(v) — O(S) scan per element (approx log N calls per sort)
for (int s = 0; s < series.size(); s++) { ops++; if (series.get(s) == v) break; }
}
return ops;
}
/** FAST: series_map built once — O(1) per element */
static long inOrderOfFast(int collectionSize, int seriesSize) {
Map<Integer, Integer> seriesMap = new HashMap<>();
for (int i = 0; i < seriesSize; i++) seriesMap.put(i, i);
long ops = 0;
for (int i = 0; i < collectionSize; i++) {
int v = i % seriesSize;
ops++; // O(1) map lookup
seriesMap.get(v);
}
return ops;
}
// ── rails-0005: SchemaDumper constraint name filtering ───────────────────
/** SLOW: constraint_names Array#include? in indexes.reject — O(I×C) */
static long schemaDumperSlow(int indexes, int constraints) {
List<String> constraintNames = new ArrayList<>();
for (int i = 0; i < constraints; i++) constraintNames.add("constraint_" + i);
long ops = 0;
// indexes.reject { |index| constraint_names.include?(index.name) }
for (int i = 0; i < indexes; i++) {
String idxName = "constraint_" + (i % (constraints * 2));
for (String c : constraintNames) { ops++; if (c.equals(idxName)) break; }
}
return ops;
}
/** FAST: constraint_names as Set — O(1) per index */
static long schemaDumperFast(int indexes, int constraints) {
Set<String> constraintSet = new HashSet<>();
for (int i = 0; i < constraints; i++) constraintSet.add("constraint_" + i);
long ops = 0;
for (int i = 0; i < indexes; i++) {
String idxName = "constraint_" + (i % (constraints * 2));
ops++; // O(1)
constraintSet.contains(idxName);
}
return ops;
}
// ── rails-0007: lazy_load_hooks @run_once Array ───────────────────────────
/** SLOW: @run_once[name].include?(block) — Array scan per hook per run_load_hooks */
static long lazyLoadHooksSlow(int hooks, int runOnceCount) {
List<Integer> runOnce = new ArrayList<>();
for (int i = 0; i < runOnceCount; i++) runOnce.add(i);
long ops = 0;
for (int h = 0; h < hooks; h++) {
// @run_once[name].include?(block) — O(R) scan
for (int r : runOnce) { ops++; if (r == h % runOnceCount) break; }
}
return ops;
}
/** FAST: @run_once[name] as Set — O(1) include? per hook */
static long lazyLoadHooksFast(int hooks, int runOnceCount) {
Set<Integer> runOnceSet = new HashSet<>();
for (int i = 0; i < runOnceCount; i++) runOnceSet.add(i);
long ops = 0;
for (int h = 0; h < hooks; h++) {
ops++; // O(1) set lookup
runOnceSet.contains(h % runOnceCount);
}
return ops;
}
// ── rails-0008: Enum value_method_names ──────────────────────────────────
/** SLOW: value_method_names.include? inside pairs.each — O(E²) */
static long enumValuesSlow(int enumValues) {
List<String> names = new ArrayList<>();
long ops = 0;
for (int i = 0; i < enumValues; i++) {
String name = "status_" + i;
String alias_ = "is_status_" + i;
names.add(name);
// !value_method_names.include?(alias) — O(E) scan
for (String n : names) { ops++; if (n.equals(alias_)) break; }
names.add(alias_);
}
return ops;
}
/** FAST: value_method_names as Set — O(1) include? per pair */
static long enumValuesFast(int enumValues) {
Set<String> names = new HashSet<>();
long ops = 0;
for (int i = 0; i < enumValues; i++) {
String name = "status_" + i;
String alias_ = "is_status_" + i;
names.add(name);
ops++; // O(1) set lookup
names.contains(alias_);
names.add(alias_);
}
return ops;
}
// ── rails-0009: FilterAttributeHandler filter_parameters Array ───────────
/** SLOW: filter_parameters Array#include? called per attribute per class — O(A×F) */
static long filterAttrHandlerSlow(int attributes, int existingFilters) {
List<String> filterParams = new ArrayList<>();
for (int i = 0; i < existingFilters; i++) filterParams.add("existing_filter_" + i);
long ops = 0;
// list.each { app.config.filter_parameters << filter unless filter_parameters.include?(filter) }
for (int a = 0; a < attributes; a++) {
String filter = "model.attr_" + a;
for (String f : filterParams) { ops++; if (f.equals(filter)) break; }
filterParams.add(filter);
}
return ops;
}
/** FAST: pre-build Set of filter_parameters — O(1) per attribute */
static long filterAttrHandlerFast(int attributes, int existingFilters) {
List<String> filterParams = new ArrayList<>();
Set<String> filterSet = new HashSet<>();
for (int i = 0; i < existingFilters; i++) {
filterParams.add("existing_filter_" + i);
filterSet.add("existing_filter_" + i);
}
long ops = 0;
for (int a = 0; a < attributes; a++) {
String filter = "model.attr_" + a;
ops++;
if (!filterSet.contains(filter)) {
filterParams.add(filter);
filterSet.add(filter);
}
}
return ops;
}
// ── rails-0010: Encryption::AutoFilteredParameters two Array scans ───────
/** SLOW: Array#include? on filter_params + Array#find on excluded_list per attribute — O(A×(F+X)) */
static long encryptionFilterSlow(int encryptedAttrs, int filterParams, int excludedCount) {
List<String> fp = new ArrayList<>();
for (int i = 0; i < filterParams; i++) fp.add("existing_" + i);
List<String> excluded = new ArrayList<>();
for (int i = 0; i < excludedCount; i++) excluded.add("excluded_" + i);
long ops = 0;
for (int a = 0; a < encryptedAttrs; a++) {
String filter = "model.secret_" + a;
// excluded_from_filter_parameters?.find — O(X)
for (String ex : excluded) { ops++; if (ex.equals(filter)) break; }
// filter_parameters.include? — O(F)
for (String f : fp) { ops++; if (f.equals(filter)) break; }
fp.add(filter);
}
return ops;
}
/** FAST: pre-build Sets for both lists — O(1) per attribute */
static long encryptionFilterFast(int encryptedAttrs, int filterParams, int excludedCount) {
Set<String> fpSet = new HashSet<>();
for (int i = 0; i < filterParams; i++) fpSet.add("existing_" + i);
Set<String> exSet = new HashSet<>();
for (int i = 0; i < excludedCount; i++) exSet.add("excluded_" + i);
long ops = 0;
for (int a = 0; a < encryptedAttrs; a++) {
String filter = "model.secret_" + a;
ops++; // excluded check O(1)
if (!exSet.contains(filter)) {
ops++; // filter_params check O(1)
if (!fpSet.contains(filter)) {
fpSet.add(filter);
}
}
}
return ops;
}
// ── rails-0011: TimeZoneConversion skip_list Array per column ─────────────
/** SLOW: skip_time_zone_conversion_for_attributes.include? per column per class — O(M×C×S) */
static long tzConversionSlow(int models, int columns, int skipListSize) {
List<String> skipList = new ArrayList<>();
for (int i = 0; i < skipListSize; i++) skipList.add("skip_col_" + i);
long ops = 0;
for (int m = 0; m < models; m++) {
// create_time_zone_conversion_attribute? called per column
for (int c = 0; c < columns; c++) {
String colName = "col_" + (c % (skipListSize * 2));
// skip_time_zone_conversion_for_attributes.include?(name) — O(S)
for (String s : skipList) { ops++; if (s.equals(colName)) break; }
}
}
return ops;
}
/** FAST: skip_list materialized as Set once per class — O(1) per column */
static long tzConversionFast(int models, int columns, int skipListSize) {
List<String> skipList = new ArrayList<>();
for (int i = 0; i < skipListSize; i++) skipList.add("skip_col_" + i);
long ops = 0;
for (int m = 0; m < models; m++) {
Set<String> skipSet = new HashSet<>(skipList); // O(S) once per class
for (int c = 0; c < columns; c++) {
String colName = "col_" + (c % (skipListSize * 2));
ops++; // O(1) set lookup
skipSet.contains(colName);
}
}
return ops;
}
// ── rails-0012: options_for_select selected/disabled array ───────────────
/** SLOW: selected/disabled as Array — include? O(S) per option element */
static long optionsForSelectSlow(int numOptions, int numSelected) {
List<String> selected = new ArrayList<>();
for (int i = 0; i < numSelected; i++) selected.add("v" + i);
long ops = 0;
// container.map — per element check Array#include?
for (int i = 0; i < numOptions; i++) {
String value = "v" + (i % (numSelected * 2));
// Array(selected).include? value — O(S) scan
for (String s : selected) { ops++; if (s.equals(value)) break; }
}
return ops;
}
/** FAST: selected/disabled as Set — O(1) per option */
static long optionsForSelectFast(int numOptions, int numSelected) {
Set<String> selectedSet = new HashSet<>();
for (int i = 0; i < numSelected; i++) selectedSet.add("v" + i);
long ops = 0;
for (int i = 0; i < numOptions; i++) {
String value = "v" + (i % (numSelected * 2));
ops++; // O(1) set lookup
selectedSet.contains(value);
}
return ops;
}
// ── rails-0013: CollectionHelpers render_collection selected set ─────────
/** SLOW: Array(current_value).map.include? rebuilt per item per option type */
static long collectionHelpersSlow(int collSize, int optionValues, int optionTypes) {
// simulate [:checked, :selected, :disabled, :readonly] × collection size
List<String> optArr = new ArrayList<>();
for (int i = 0; i < optionValues; i++) optArr.add("item_" + i);
long ops = 0;
for (int item = 0; item < collSize; item++) {
String value = "item_" + (item % (optionValues * 2));
for (int t = 0; t < optionTypes; t++) {
// Array(current_value).map(&:to_s).include?(value.to_s) per option type
for (String v : optArr) { ops++; if (v.equals(value)) break; }
}
}
return ops;
}
/** FAST: Sets pre-built before render_collection loop */
static long collectionHelpersFast(int collSize, int optionValues, int optionTypes) {
Set<String> optSet = new HashSet<>();
for (int i = 0; i < optionValues; i++) optSet.add("item_" + i);
long ops = 0;
for (int item = 0; item < collSize; item++) {
String value = "item_" + (item % (optionValues * 2));
for (int t = 0; t < optionTypes; t++) {
ops++; // O(1) set lookup
optSet.contains(value);
}
}
return ops;
}
// ── rails-0014: ActiveJob::Arguments symbol_keys array in transform_keys ──
/** SLOW: symbol_keys.include? Array scan inside transform_keys loop */
static long symbolKeysSlow(int hashKeys, int symbolKeys) {
List<String> symArr = new ArrayList<>();
for (int i = 0; i < symbolKeys; i++) symArr.add("key_" + i);
long ops = 0;
// hash.to_h.transform_keys — iterate all hash keys, check each against symbol_keys
for (int k = 0; k < hashKeys; k++) {
String key = "key_" + (k % (symbolKeys * 2));
for (String s : symArr) { ops++; if (s.equals(key)) break; }
}
return ops;
}
/** FAST: convert symbol_keys to Set before the loop */
static long symbolKeysFast(int hashKeys, int symbolKeys) {
Set<String> symSet = new HashSet<>();
for (int i = 0; i < symbolKeys; i++) symSet.add("key_" + i);
long ops = 0;
for (int k = 0; k < hashKeys; k++) {
String key = "key_" + (k % (symbolKeys * 2));
ops++; // O(1) set lookup
symSet.contains(key);
}
return ops;
}
// ── rails-0015: schema_statements detect+count duplicate versions ─────────
/** SLOW: inserting.detect { |v| inserting.count(v) > 1 } — O(V²) */
static long duplicateVersionSlow(int versions) {
List<Integer> inserting = new ArrayList<>();
for (int i = 0; i < versions; i++) inserting.add(i * 100);
// no actual duplicate; worst case scans all
long ops = 0;
Integer dup = null;
for (Integer v : inserting) {
int c = 0;
for (Integer x : inserting) { ops++; if (x.equals(v)) c++; }
if (c > 1) { dup = v; break; }
}
return ops;
}
/** FAST: tally-based frequency map, O(V) */
static long duplicateVersionFast(int versions) {
List<Integer> inserting = new ArrayList<>();
for (int i = 0; i < versions; i++) inserting.add(i * 100);
long ops = 0;
// build frequency map in one pass
Map<Integer, Integer> freq = new HashMap<>();
for (Integer v : inserting) { ops++; freq.merge(v, 1, Integer::sum); }
// scan for duplicate once
Integer dup = null;
for (Map.Entry<Integer, Integer> e : freq.entrySet()) {
ops++;
if (e.getValue() > 1) { dup = e.getKey(); break; }
}
return ops;
}
// ── rails-0016: SQLite3 copy_table_indexes/copy_table_contents ───────────
/** SLOW: to_column_names.include? Array scan inside indexes.each × columns.select */
static long sqlite3CopyIndexesSlow(int numIndexes, int colsPerIndex, int tableColumns) {
List<String> toColumns = new ArrayList<>();
for (int i = 0; i < tableColumns; i++) toColumns.add("col_" + i);
long ops = 0;
for (int idx = 0; idx < numIndexes; idx++) {
// per index: to_column_names rebuilt as Array, then scanned per column
for (int c = 0; c < colsPerIndex; c++) {
String col = "col_" + (c % (tableColumns * 2));
for (String tc : toColumns) { ops++; if (tc.equals(col)) break; }
}
}
return ops;
}
/** FAST: to_column_names as Set — built once per (or before) index loop */
static long sqlite3CopyIndexesFast(int numIndexes, int colsPerIndex, int tableColumns) {
Set<String> toColSet = new HashSet<>();
for (int i = 0; i < tableColumns; i++) toColSet.add("col_" + i);
long ops = 0;
for (int idx = 0; idx < numIndexes; idx++) {
for (int c = 0; c < colsPerIndex; c++) {
String col = "col_" + (c % (tableColumns * 2));
ops++; // O(1) set lookup
toColSet.contains(col);
}
}
return ops;
}
// ── rails-0017: schema_statements rename_column_indexes ──────────────────
/**
* SLOW: index.columns.include?(new_column_name) inside indexes(table).each — O(I×C)
*
* Ruby original (schema_statements.rb):
* indexes(table_name).each do |index|
* next unless index.columns.include?(new_column_name) # Array scan O(C)
* old_columns = index.columns.dup
* old_columns[old_columns.index(new_column_name)] = column_name # Array#index O(C)
*
* index.columns is a plain Array of column name strings.
* For every index we pay O(C) for the include? guard and O(C) for the position lookup.
* Total: O(I × C) where I = number of indexes, C = columns per index.
* A wide table migrated by rename_column can have I=50, C=10 → 1000 string comparisons
* per rename_column call, multiplied across every migration in the batch.
*/
static long renameColumnIndexesSlow(int numIndexes, int colsPerIndex) {
long ops = 0;
for (int idx = 0; idx < numIndexes; idx++) {
// simulate index.columns as Array
List<String> cols = new ArrayList<>();
for (int c = 0; c < colsPerIndex; c++) cols.add("col_" + c);
String target = "col_" + (colsPerIndex - 1); // worst-case: target is last
// include? guard — O(C) scan
for (String col : cols) { ops++; if (col.equals(target)) break; }
// Array#index — O(C) position scan (only if include? found it)
for (int i = 0; i < cols.size(); i++) { ops++; if (cols.get(i).equals(target)) break; }
}
return ops;
}
/** FAST: convert index.columns to Set for O(1) include?, then use indexOf once */
static long renameColumnIndexesFast(int numIndexes, int colsPerIndex) {
long ops = 0;
for (int idx = 0; idx < numIndexes; idx++) {
List<String> cols = new ArrayList<>();
Set<String> colSet = new HashSet<>();
for (int c = 0; c < colsPerIndex; c++) {
String name = "col_" + c;
cols.add(name);
colSet.add(name);
}
String target = "col_" + (colsPerIndex - 1);
ops++; // O(1) Set#include?
if (colSet.contains(target)) {
ops++; // Array#indexOf once for position — O(C) but not the hot path
cols.indexOf(target);
}
}
return ops;
}
// ── rails-0018: CollectionAssociation#find_by_scan ────────────────────────
/** SLOW: ids is Array — Array#include? per loaded record O(T×I) */
static long collectionFindScanSlow(int targetSize, int idsCount) {
// Simulate load_target: T in-memory records
List<String> target = new ArrayList<>();
for (int i = 0; i < targetSize; i++) target.add("rec_" + i);
// ids = args.flatten.compact.map(&:to_s).uniq — returns Array
List<String> ids = new ArrayList<>();
for (int i = 0; i < idsCount; i++) ids.add("rec_" + (i * 3)); // request every 3rd
long ops = 0;
// load_target.select { |r| ids.include?(r.id.to_s) }
for (String rec : target) {
for (String id : ids) {
ops++;
if (id.equals(rec)) break;
}
}
return ops;
}
/** FAST: ids_set is HashSet — Set#include? per record O(T+I) */
static long collectionFindScanFast(int targetSize, int idsCount) {
List<String> target = new ArrayList<>();
for (int i = 0; i < targetSize; i++) target.add("rec_" + i);
// ids_set = ids.to_set — O(I) one-time build
Set<String> idsSet = new HashSet<>();
for (int i = 0; i < idsCount; i++) idsSet.add("rec_" + (i * 3));
long ops = 0;
// load_target.select { |r| ids_set.include?(r.id.to_s) }
for (String rec : target) {
ops++; // O(1) Set#include?
idsSet.contains(rec);
}
return ops;
}
static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) {
slow.run(); fast.run();
long t0 = System.nanoTime(); slow.run(); long sMs = (System.nanoTime()-t0)/1_000_000;
long t1 = System.nanoTime(); fast.run(); long fMs = (System.nanoTime()-t1)/1_000_000;
double r = fOps > 0 ? (double)sOps/fOps : 0;
System.out.printf(" %-48s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.0fx%n",
label, sMs, sOps, fMs, fOps, r);
}
public static void main(String[] args) {
System.out.println("=== UNIT rails-0001..0018: Ruby on Rails CWE-407 ===");
System.out.println();
final int LOADERS=500, FUTURE=300, ROUNDS=20;
final int DESC=50, FILTERS=100, CHAIN=200;
final int RECV=5000, EXCL=500;
final int COLL=3000, SERIES=300;
final int IDXS=500, CONSTR=200;
final int HOOKS=1000, RUN_ONCE=500;
final int ENUM=1000;
final int ATTRS=500, EXISTING_FP=200;
final int ENC_ATTRS=500, FP_SIZE=200, EXCL_SIZE=50;
final int MODELS=100, COLS=50, SKIP=20;
long s0=preloaderSlow(LOADERS,FUTURE,ROUNDS), f0=preloaderFast(LOADERS,FUTURE,ROUNDS);
bench("rails-0001 Preloader::Batch future_tables", ()->preloaderSlow(LOADERS,FUTURE,ROUNDS), ()->preloaderFast(LOADERS,FUTURE,ROUNDS), s0, f0);
long s1=callbacksSlow(DESC,FILTERS,CHAIN), f1=callbacksFast(DESC,FILTERS,CHAIN);
bench("rails-0002 Callbacks chain.index", ()->callbacksSlow(DESC,FILTERS,CHAIN), ()->callbacksFast(DESC,FILTERS,CHAIN), s1, f1);
long s2=excludingSlow(RECV,EXCL), f2=excludingFast(RECV,EXCL);
bench("rails-0003 Enumerable#excluding elements.include", ()->excludingSlow(RECV,EXCL), ()->excludingFast(RECV,EXCL), s2, f2);
long s3=inOrderOfSlow(COLL,SERIES), f3=inOrderOfFast(COLL,SERIES);
bench("rails-0004 Enumerable#in_order_of series.index", ()->inOrderOfSlow(COLL,SERIES), ()->inOrderOfFast(COLL,SERIES), s3, f3);
long s4=schemaDumperSlow(IDXS,CONSTR), f4=schemaDumperFast(IDXS,CONSTR);
bench("rails-0005/6 SchemaDumper constraint names", ()->schemaDumperSlow(IDXS,CONSTR), ()->schemaDumperFast(IDXS,CONSTR), s4, f4);
long s5=lazyLoadHooksSlow(HOOKS,RUN_ONCE), f5=lazyLoadHooksFast(HOOKS,RUN_ONCE);
bench("rails-0007 lazy_load_hooks @run_once", ()->lazyLoadHooksSlow(HOOKS,RUN_ONCE), ()->lazyLoadHooksFast(HOOKS,RUN_ONCE), s5, f5);
long s6=enumValuesSlow(ENUM), f6=enumValuesFast(ENUM);
bench("rails-0008 Enum value_method_names", ()->enumValuesSlow(ENUM), ()->enumValuesFast(ENUM), s6, f6);
long s7=filterAttrHandlerSlow(ATTRS,EXISTING_FP), f7=filterAttrHandlerFast(ATTRS,EXISTING_FP);
bench("rails-0009 FilterAttributeHandler filter_params", ()->filterAttrHandlerSlow(ATTRS,EXISTING_FP), ()->filterAttrHandlerFast(ATTRS,EXISTING_FP), s7, f7);
long s8=encryptionFilterSlow(ENC_ATTRS,FP_SIZE,EXCL_SIZE), f8=encryptionFilterFast(ENC_ATTRS,FP_SIZE,EXCL_SIZE);
bench("rails-0010 Encryption::AutoFilteredParams", ()->encryptionFilterSlow(ENC_ATTRS,FP_SIZE,EXCL_SIZE), ()->encryptionFilterFast(ENC_ATTRS,FP_SIZE,EXCL_SIZE), s8, f8);
long s9=tzConversionSlow(MODELS,COLS,SKIP), f9=tzConversionFast(MODELS,COLS,SKIP);
bench("rails-0011 TimeZoneConversion skip_list", ()->tzConversionSlow(MODELS,COLS,SKIP), ()->tzConversionFast(MODELS,COLS,SKIP), s9, f9);
final int OPT_N=500, OPT_S=50;
long s10=optionsForSelectSlow(OPT_N,OPT_S), f10=optionsForSelectFast(OPT_N,OPT_S);
bench("rails-0012 options_for_select selected Array", ()->optionsForSelectSlow(OPT_N,OPT_S), ()->optionsForSelectFast(OPT_N,OPT_S), s10, f10);
final int COLL_SIZE=200, COLL_VALS=20, OPT_TYPES=4;
long s11=collectionHelpersSlow(COLL_SIZE,COLL_VALS,OPT_TYPES), f11=collectionHelpersFast(COLL_SIZE,COLL_VALS,OPT_TYPES);
bench("rails-0013 CollectionHelpers option Array rebuild", ()->collectionHelpersSlow(COLL_SIZE,COLL_VALS,OPT_TYPES), ()->collectionHelpersFast(COLL_SIZE,COLL_VALS,OPT_TYPES), s11, f11);
final int HASH_KEYS=100, SYM_KEYS=30;
long s12=symbolKeysSlow(HASH_KEYS,SYM_KEYS), f12=symbolKeysFast(HASH_KEYS,SYM_KEYS);
bench("rails-0014 ActiveJob symbol_keys Array", ()->symbolKeysSlow(HASH_KEYS,SYM_KEYS), ()->symbolKeysFast(HASH_KEYS,SYM_KEYS), s12, f12);
final int DUP_VERS=500;
long s13=duplicateVersionSlow(DUP_VERS), f13=duplicateVersionFast(DUP_VERS);
bench("rails-0015 schema_statements detect+count O(V²)", ()->duplicateVersionSlow(DUP_VERS), ()->duplicateVersionFast(DUP_VERS), s13, f13);
final int IDXS2=20, COLS_PER=10, TCOLS=50;
long s14=sqlite3CopyIndexesSlow(IDXS2,COLS_PER,TCOLS), f14=sqlite3CopyIndexesFast(IDXS2,COLS_PER,TCOLS);
bench("rails-0016 SQLite3 copy_table to_column_names Array", ()->sqlite3CopyIndexesSlow(IDXS2,COLS_PER,TCOLS), ()->sqlite3CopyIndexesFast(IDXS2,COLS_PER,TCOLS), s14, f14);
final int RCI_IDXS=500, RCI_COLS=30;
long s15=renameColumnIndexesSlow(RCI_IDXS,RCI_COLS), f15=renameColumnIndexesFast(RCI_IDXS,RCI_COLS);
bench("rails-0017 rename_column_indexes columns.include?", ()->renameColumnIndexesSlow(RCI_IDXS,RCI_COLS), ()->renameColumnIndexesFast(RCI_IDXS,RCI_COLS), s15, f15);
final int COLL_TARGET=2000, FIND_IDS=100;
long s16=collectionFindScanSlow(COLL_TARGET,FIND_IDS), f16=collectionFindScanFast(COLL_TARGET,FIND_IDS);
bench("rails-0018 CollectionAssociation find_by_scan ids", ()->collectionFindScanSlow(COLL_TARGET,FIND_IDS), ()->collectionFindScanFast(COLL_TARGET,FIND_IDS), s16, f16);
System.out.println();
int pass = 0;
assert s0 > f0 * 10 : "rails-0001 expected >10x"; pass++;
assert s1 > f1 * 5 : "rails-0002 expected >5x"; pass++;
assert s2 > f2 * 5 : "rails-0003 expected >5x"; pass++;
assert s3 > f3 * 5 : "rails-0004 expected >5x"; pass++;
assert s4 > f4 * 5 : "rails-0005 expected >5x"; pass++;
assert s5 > f5 * 5 : "rails-0007 expected >5x"; pass++;
assert s6 > f6 * 5 : "rails-0008 expected >5x"; pass++;
assert s7 > f7 * 5 : "rails-0009 expected >5x"; pass++;
assert s8 > f8 * 5 : "rails-0010 expected >5x"; pass++;
assert s9 > f9 * 5 : "rails-0011 expected >5x"; pass++;
assert s10 > f10 * 5 : "rails-0012 expected >5x"; pass++;
assert s11 > f11 * 5 : "rails-0013 expected >5x"; pass++;
assert s12 > f12 * 5 : "rails-0014 expected >5x"; pass++;
assert s13 > f13 * 5 : "rails-0015 expected >5x"; pass++;
assert s14 > f14 * 5 : "rails-0016 expected >5x"; pass++;
assert s15 > f15 * 5 : "rails-0017 expected >5x"; pass++;
assert s16 > f16 * 5 : "rails-0018 expected >5x"; pass++;
assert preloaderFast(10,5,2) >= 0; pass++;
System.out.printf("%d/18 PASS — rails-0001..0018: CWE-407 in preloader/callbacks/enumerable/schema/hooks/enum/filter/encryption/timezone/view/job/sqlite/rename_column/collection_find%n", pass);
System.out.printf("Hotpaths: Preloader::Batch, skip_callback, Enumerable#excluding, SchemaDumper, lazy_load_hooks, FilterAttributeHandler, AutoFilteredParams, TimeZoneConversion, options_for_select, CollectionHelpers, ActiveJob::Arguments, schema_statements, SQLite3Adapter, rename_column_indexes, CollectionAssociation#find_by_scan%n");
}
}