Skip to content

Commit a3fa4b3

Browse files
committed
Create a test to show that only assets which have changed are reprocessed.
1 parent fe413dc commit a3fa4b3

File tree

1 file changed

+187
-0
lines changed

1 file changed

+187
-0
lines changed

crates/bevy_asset/src/processor/tests.rs

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,3 +1319,190 @@ fn clears_invalid_data_from_processed_dir() {
13191319
assert!(default_processed_dir.get_dir(empty_dir_subdir).is_none());
13201320
assert!(default_processed_dir.get_dir(empty_dir).is_none());
13211321
}
1322+
1323+
#[test]
1324+
fn only_reprocesses_wrong_hash_on_startup() {
1325+
let no_deps_asset = Path::new("no_deps.cool.ron");
1326+
let source_changed_asset = Path::new("source_changed.cool.ron");
1327+
let dep_unchanged_asset = Path::new("dep_unchanged.cool.ron");
1328+
let dep_changed_asset = Path::new("dep_changed.cool.ron");
1329+
let default_source_dir;
1330+
let default_processed_dir;
1331+
1332+
#[derive(TypePath, Clone)]
1333+
struct MergeEmbeddedAndAddText;
1334+
1335+
impl MutateAsset<CoolText> for MergeEmbeddedAndAddText {
1336+
fn mutate(&self, asset: &mut CoolText) {
1337+
asset.text.push_str(" processed");
1338+
if asset.embedded.is_empty() {
1339+
return;
1340+
}
1341+
asset.text.push(' ');
1342+
asset.text.push_str(&asset.embedded);
1343+
}
1344+
}
1345+
1346+
#[derive(TypePath, Clone)]
1347+
struct Count<T>(Arc<Mutex<u32>>, T);
1348+
1349+
impl<A: Asset, T: MutateAsset<A>> MutateAsset<A> for Count<T> {
1350+
fn mutate(&self, asset: &mut A) {
1351+
*self.0.lock().unwrap_or_else(PoisonError::into_inner) += 1;
1352+
self.1.mutate(asset);
1353+
}
1354+
}
1355+
1356+
let transformer = Count(Arc::new(Mutex::new(0)), MergeEmbeddedAndAddText);
1357+
type CoolTextProcessor = LoadTransformAndSave<
1358+
CoolTextLoader,
1359+
RootAssetTransformer<Count<MergeEmbeddedAndAddText>, CoolText>,
1360+
CoolTextSaver,
1361+
>;
1362+
1363+
// Create a scope so that the app is completely gone afterwards (and we can see what happens
1364+
// after reinitializing).
1365+
{
1366+
let AppWithProcessor {
1367+
mut app,
1368+
source_gate,
1369+
default_source_dirs,
1370+
..
1371+
} = create_app_with_asset_processor(&[]);
1372+
default_source_dir = default_source_dirs.source;
1373+
default_processed_dir = default_source_dirs.processed;
1374+
1375+
app.init_asset::<CoolText>()
1376+
.init_asset::<SubText>()
1377+
.register_asset_loader(CoolTextLoader)
1378+
.register_asset_processor(CoolTextProcessor::new(
1379+
RootAssetTransformer::new(transformer.clone()),
1380+
CoolTextSaver,
1381+
))
1382+
.set_default_asset_processor::<CoolTextProcessor>("cool.ron");
1383+
1384+
let guard = source_gate.write_blocking();
1385+
1386+
let cool_text_with_embedded = |text: &str, embedded: &Path| {
1387+
let cool_text_ron = CoolTextRon {
1388+
text: text.into(),
1389+
dependencies: vec![],
1390+
embedded_dependencies: vec![embedded.to_string_lossy().into_owned()],
1391+
sub_texts: vec![],
1392+
};
1393+
ron::ser::to_string_pretty(&cool_text_ron, PrettyConfig::new().new_line("\n")).unwrap()
1394+
};
1395+
1396+
default_source_dir.insert_asset_text(no_deps_asset, &serialize_as_cool_text("no_deps"));
1397+
default_source_dir.insert_asset_text(
1398+
source_changed_asset,
1399+
&serialize_as_cool_text("source_changed"),
1400+
);
1401+
default_source_dir.insert_asset_text(
1402+
dep_unchanged_asset,
1403+
&cool_text_with_embedded("dep_unchanged", no_deps_asset),
1404+
);
1405+
default_source_dir.insert_asset_text(
1406+
dep_changed_asset,
1407+
&cool_text_with_embedded("dep_changed", source_changed_asset),
1408+
);
1409+
1410+
run_app_until_finished_processing(&mut app, guard);
1411+
1412+
assert_eq!(
1413+
read_asset_as_string(&default_processed_dir, no_deps_asset),
1414+
serialize_as_cool_text("no_deps processed")
1415+
);
1416+
assert_eq!(
1417+
read_asset_as_string(&default_processed_dir, source_changed_asset),
1418+
serialize_as_cool_text("source_changed processed")
1419+
);
1420+
assert_eq!(
1421+
read_asset_as_string(&default_processed_dir, dep_unchanged_asset),
1422+
serialize_as_cool_text("dep_unchanged processed no_deps processed")
1423+
);
1424+
assert_eq!(
1425+
read_asset_as_string(&default_processed_dir, dep_changed_asset),
1426+
serialize_as_cool_text("dep_changed processed source_changed processed")
1427+
);
1428+
}
1429+
1430+
// Assert and reset the processing count.
1431+
assert_eq!(
1432+
core::mem::take(&mut *transformer.0.lock().unwrap_or_else(PoisonError::into_inner)),
1433+
4
1434+
);
1435+
1436+
// Hand-make the app, since we need to pass in our already existing Dirs from the last app.
1437+
let mut app = App::new();
1438+
let source_gate = Arc::new(RwLock::new(()));
1439+
1440+
let source_memory_reader = LockGatedReader::new(
1441+
source_gate.clone(),
1442+
MemoryAssetReader {
1443+
root: default_source_dir.clone(),
1444+
},
1445+
);
1446+
let processed_memory_reader = MemoryAssetReader {
1447+
root: default_processed_dir.clone(),
1448+
};
1449+
let processed_memory_writer = MemoryAssetWriter {
1450+
root: default_processed_dir.clone(),
1451+
};
1452+
1453+
app.register_asset_source(
1454+
AssetSourceId::Default,
1455+
AssetSourceBuilder::new(move || Box::new(source_memory_reader.clone()))
1456+
.with_processed_reader(move || Box::new(processed_memory_reader.clone()))
1457+
.with_processed_writer(move |_| Some(Box::new(processed_memory_writer.clone()))),
1458+
);
1459+
1460+
app.add_plugins((
1461+
TaskPoolPlugin::default(),
1462+
AssetPlugin {
1463+
mode: AssetMode::Processed,
1464+
use_asset_processor_override: Some(true),
1465+
..Default::default()
1466+
},
1467+
));
1468+
1469+
app.init_asset::<CoolText>()
1470+
.init_asset::<SubText>()
1471+
.register_asset_loader(CoolTextLoader)
1472+
.register_asset_processor(CoolTextProcessor::new(
1473+
RootAssetTransformer::new(transformer.clone()),
1474+
CoolTextSaver,
1475+
))
1476+
.set_default_asset_processor::<CoolTextProcessor>("cool.ron");
1477+
1478+
let guard = source_gate.write_blocking();
1479+
1480+
default_source_dir
1481+
.insert_asset_text(source_changed_asset, &serialize_as_cool_text("DIFFERENT"));
1482+
1483+
run_app_until_finished_processing(&mut app, guard);
1484+
1485+
// Only source_changed and dep_changed assets were reprocessed - all others still have the same
1486+
// hashes.
1487+
assert_eq!(
1488+
*transformer.0.lock().unwrap_or_else(PoisonError::into_inner),
1489+
2
1490+
);
1491+
1492+
assert_eq!(
1493+
read_asset_as_string(&default_processed_dir, no_deps_asset),
1494+
serialize_as_cool_text("no_deps processed")
1495+
);
1496+
assert_eq!(
1497+
read_asset_as_string(&default_processed_dir, source_changed_asset),
1498+
serialize_as_cool_text("DIFFERENT processed")
1499+
);
1500+
assert_eq!(
1501+
read_asset_as_string(&default_processed_dir, dep_unchanged_asset),
1502+
serialize_as_cool_text("dep_unchanged processed no_deps processed")
1503+
);
1504+
assert_eq!(
1505+
read_asset_as_string(&default_processed_dir, dep_changed_asset),
1506+
serialize_as_cool_text("dep_changed processed DIFFERENT processed")
1507+
);
1508+
}

0 commit comments

Comments
 (0)