From 5780e4d44df97269ba988f95cabb14781f17e91b Mon Sep 17 00:00:00 2001 From: vicnaum Date: Tue, 14 Nov 2023 18:06:31 +0100 Subject: [PATCH] test: SVG tests added --- .gitignore | 2 + foundry.toml | 3 +- initSvgDirs.sh | 17 ++ test/token-uris/FollowSVGTest.t.sol | 26 +++ test/token-uris/HandleSVGTest.t.sol | 69 ++++++++ test/token-uris/ProfileSVGTest.t.sol | 247 +++++++++++++++++++++++++++ 6 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 initSvgDirs.sh create mode 100644 test/token-uris/FollowSVGTest.t.sol create mode 100644 test/token-uris/HandleSVGTest.t.sol create mode 100644 test/token-uris/ProfileSVGTest.t.sol diff --git a/.gitignore b/.gitignore index b249362..e8fa96c 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ docs/ contracts/core/modules/follow/SecretCodeFollowModule.sol .DS_Store + +/svgs diff --git a/foundry.toml b/foundry.toml index 18f2d72..aef30a0 100644 --- a/foundry.toml +++ b/foundry.toml @@ -4,7 +4,8 @@ out = 'out' libs = ['node_modules', 'lib'] test = 'test' cache_path = 'forge-cache' -fs_permissions = [{ access = "read-write", path = "./"}] +fs_permissions = [{ access = "read-write", path = "./"},{ access = "write", path = "./svgs"}] + solc_version = '0.8.21' evm_version = 'paris' optimizer = true diff --git a/initSvgDirs.sh b/initSvgDirs.sh new file mode 100644 index 0000000..3bfaa4c --- /dev/null +++ b/initSvgDirs.sh @@ -0,0 +1,17 @@ +rm -rf svgs +mkdir svgs +cd svgs +mkdir background +mkdir skin +mkdir legs +mkdir shoes +mkdir faces +mkdir body +mkdir logo +mkdir headwear +mkdir profiles_gold +mkdir profiles +mkdir profiles_fuzz + +mkdir follows +mkdir handles diff --git a/test/token-uris/FollowSVGTest.t.sol b/test/token-uris/FollowSVGTest.t.sol new file mode 100644 index 0000000..e87ba1d --- /dev/null +++ b/test/token-uris/FollowSVGTest.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import 'forge-std/Test.sol'; + +import {FollowSVG} from 'contracts/libraries/svgs/Follow/FollowSVG.sol'; + +contract FollowNFT { + function tryWithTokenId(uint256 tokenId) external pure returns (string memory) { + return FollowSVG.getFollowSVG(tokenId); + } +} + +contract FollowSVGTest is Test { + FollowNFT followNFT; + string constant dir = 'svgs/'; + + function setUp() public { + followNFT = new FollowNFT(); + } + + function testTest() public { + vm.writeFile(string.concat(dir, 'follows/follow_1_gold.svg'), followNFT.tryWithTokenId(1)); + vm.writeFile(string.concat(dir, 'follows/follow_11_normal.svg'), followNFT.tryWithTokenId(11)); + } +} diff --git a/test/token-uris/HandleSVGTest.t.sol b/test/token-uris/HandleSVGTest.t.sol new file mode 100644 index 0000000..fd18ad8 --- /dev/null +++ b/test/token-uris/HandleSVGTest.t.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import 'forge-std/Test.sol'; + +import {HandleSVG} from 'contracts/libraries/svgs/Handle/HandleSVG.sol'; + +contract HandleNFT { + function tryWithName(string memory name) external pure returns (string memory) { + return HandleSVG.getHandleSVG(name); + } +} + +contract HandleSVGTest is Test { + HandleNFT handleNFT; + string constant dir = 'svgs/'; + + function setUp() public { + handleNFT = new HandleNFT(); + } + + function testHandles() public { + vm.writeFile(string.concat(dir, 'handles/handle_1_black.svg'), handleNFT.tryWithName('x')); + vm.writeFile(string.concat(dir, 'handles/handle_2_gold.svg'), handleNFT.tryWithName('gm')); + vm.writeFile(string.concat(dir, 'handles/handle_3_blue.svg'), handleNFT.tryWithName('eth')); + vm.writeFile(string.concat(dir, 'handles/handle_4_purple.svg'), handleNFT.tryWithName('aave')); + vm.writeFile(string.concat(dir, 'handles/handle_5_peach.svg'), handleNFT.tryWithName('stani')); + vm.writeFile(string.concat(dir, 'handles/handle_6_green.svg'), handleNFT.tryWithName('victor')); + vm.writeFile(string.concat(dir, 'handles/handle_7.svg'), handleNFT.tryWithName('abcdefg')); + vm.writeFile(string.concat(dir, 'handles/handle_8.svg'), handleNFT.tryWithName('abcdefgh')); + vm.writeFile(string.concat(dir, 'handles/handle_9.svg'), handleNFT.tryWithName('abcdefghj')); + vm.writeFile(string.concat(dir, 'handles/handle_10.svg'), handleNFT.tryWithName('abcdefghjk')); + vm.writeFile(string.concat(dir, 'handles/handle_11.svg'), handleNFT.tryWithName('abcdefghjkl')); + vm.writeFile(string.concat(dir, 'handles/handle_12.svg'), handleNFT.tryWithName('abcdefghjklm')); + vm.writeFile(string.concat(dir, 'handles/handle_13.svg'), handleNFT.tryWithName('abcdefghjklmn')); + vm.writeFile(string.concat(dir, 'handles/handle_14.svg'), handleNFT.tryWithName('abcdefghjklmno')); + vm.writeFile(string.concat(dir, 'handles/handle_15.svg'), handleNFT.tryWithName('abcdefghjklmnop')); + vm.writeFile(string.concat(dir, 'handles/handle_16.svg'), handleNFT.tryWithName('abcdefghjklmnopq')); + vm.writeFile(string.concat(dir, 'handles/handle_17.svg'), handleNFT.tryWithName('abcdefghjklmnopqr')); + vm.writeFile(string.concat(dir, 'handles/handle_18.svg'), handleNFT.tryWithName('abcdefghjklmnopqrs')); + vm.writeFile(string.concat(dir, 'handles/handle_19.svg'), handleNFT.tryWithName('abcdefghjklmnopqrst')); + vm.writeFile(string.concat(dir, 'handles/handle_20.svg'), handleNFT.tryWithName('abcdefghjklmnopqrstu')); + vm.writeFile(string.concat(dir, 'handles/handle_21.svg'), handleNFT.tryWithName('abcdefghjklmnopqrstuv')); + vm.writeFile(string.concat(dir, 'handles/handle_22.svg'), handleNFT.tryWithName('abcdefghjklmnopqrstuvw')); + vm.writeFile(string.concat(dir, 'handles/handle_23.svg'), handleNFT.tryWithName('abcdefghjklmnopqrstuvwx')); + vm.writeFile(string.concat(dir, 'handles/handle_24.svg'), handleNFT.tryWithName('abcdefghjklmnopqrstuvwxy')); + vm.writeFile(string.concat(dir, 'handles/handle_25.svg'), handleNFT.tryWithName('abcdefghjklmnopqrstuvwxyz')); + vm.writeFile(string.concat(dir, 'handles/handle_26.svg'), handleNFT.tryWithName('abcdefghijklmnopqrstuvwxyz')); + vm.writeFile(string.concat(dir, 'handles/handle_10_numbers.svg'), handleNFT.tryWithName('0123456789')); + vm.writeFile(string.concat(dir, 'handles/handle_13_mix.svg'), handleNFT.tryWithName('abc0123456789')); + vm.writeFile( + string.concat(dir, 'handles/handle_26_superlong.svg'), + handleNFT.tryWithName('mmmmmmmm1-234567mmmmm01234') + ); + } + + function testWWW() public { + for (uint256 i = 1; i <= 26; i++) { + string memory name = ''; + for (uint256 j = 0; j < i; j++) { + name = string.concat(name, 'w'); + } + vm.writeFile( + string.concat(dir, 'handles/handle_www_', vm.toString(i), '.svg'), + handleNFT.tryWithName(name) + ); + } + } +} diff --git a/test/token-uris/ProfileSVGTest.t.sol b/test/token-uris/ProfileSVGTest.t.sol new file mode 100644 index 0000000..40ae8ab --- /dev/null +++ b/test/token-uris/ProfileSVGTest.t.sol @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import 'forge-std/Test.sol'; +import {Skin, Background, Helpers} from 'contracts/libraries/svgs/Profile/Helpers.sol'; +import {Face} from 'contracts/libraries/svgs/Profile/Face.sol'; +import {Legs} from 'contracts/libraries/svgs/Profile/Legs.sol'; +import {Shoes} from 'contracts/libraries/svgs/Profile/Shoes.sol'; +import {Body} from 'contracts/libraries/svgs/Profile/Body.sol'; +import {Hands} from 'contracts/libraries/svgs/Profile/Hands.sol'; +import {Logo} from 'contracts/libraries/svgs/Profile/Logo.sol'; +import {Headwear} from 'contracts/libraries/svgs/Profile/Headwear.sol'; + +import {ProfileSVG} from 'contracts/libraries/svgs/Profile/ProfileSVG.sol'; + +contract ProfileNFT { + function tryProfile(uint256 profileId) external pure returns (string memory) { + return ProfileSVG.getProfileSVG(profileId); + } + + function tryWithSeed(uint256 seed, bool isGold) external pure returns (string memory) { + return ProfileSVG._getSVG(seed, isGold); + } +} + +contract ProfileSVGTest is Test { + ProfileNFT profileNFT; + string constant dir = 'svgs/'; + + function setUp() public { + profileNFT = new ProfileNFT(); + } + + function _testElement(uint256 maxColors, Helpers.ComponentBytes componentByte, string memory elementName) internal { + for (uint8 i = 0; i <= maxColors + 1; i++) { + uint256 seed = setColor(i, componentByte); + console.logBytes32(bytes32(seed)); + string memory result = profileNFT.tryWithSeed(seed, i == maxColors + 1); + vm.writeFile( + string.concat( + dir, + elementName, + '/', + elementName, + '_', + i == maxColors + 1 ? 'gold' : vm.toString(i), + '.svg' + ), + result + ); + } + } + + function testBackgrounds() public { + _testElement(uint256(type(Background.BackgroundColors).max), Helpers.ComponentBytes.BACKGROUND, 'background'); + } + + function testSkins() public { + _testElement(uint256(type(Skin.SkinColors).max), Helpers.ComponentBytes.SKIN, 'skin'); + } + + function testLegs() public { + _testElement(uint256(type(Legs.LegColors).max), Helpers.ComponentBytes.LEGS, 'legs'); + } + + function testShoes() public { + _testElement(uint256(type(Shoes.ShoeColors).max), Helpers.ComponentBytes.SHOES, 'shoes'); + } + + function testFaces() public { + for (uint8 v = 0; v <= uint8(type(Face.FaceVariants).max); v++) { + for (uint8 c = 0; c <= uint8(type(Face.FaceColors).max) + 1; c++) { + uint256 seed = setVariant(v, Helpers.ComponentBytes.FACE) + setColor(c, Helpers.ComponentBytes.FACE); + string memory result = profileNFT.tryWithSeed(seed, c == uint8(type(Face.FaceColors).max) + 1); + vm.writeFile( + string.concat( + dir, + 'faces/face_', + vm.toString(v), + '_', + c == uint8(type(Face.FaceColors).max) + 1 ? 'gold' : vm.toString(c), + '.svg' + ), + result + ); + } + } + } + + function testHandsAndBody() public { + for (uint8 v = 0; v <= uint8(type(Body.BodyVariants).max); v++) { + for (uint8 c = 0; c <= uint8(type(Body.BodyColors).max); c++) { + for (uint8 h = 0; h <= uint8(type(Hands.HandsVariants).max); h++) { + for (uint8 hc = 0; hc <= uint8(type(Skin.SkinColors).max) + 1; hc++) { + uint256 seed = setVariant(v, Helpers.ComponentBytes.BODY) + + setColor(c, Helpers.ComponentBytes.BODY) + + setVariant(h, Helpers.ComponentBytes.HANDS) + + setColor(hc, Helpers.ComponentBytes.SKIN); + string memory result = profileNFT.tryWithSeed(seed, hc == uint8(type(Skin.SkinColors).max) + 1); + vm.writeFile( + string.concat( + dir, + 'body/body_b', + vm.toString(v), + '_bc', + vm.toString(c), + '_h', + vm.toString(h), + '_hc', + hc == uint8(type(Skin.SkinColors).max) + 1 ? 'gold' : vm.toString(hc), + '.svg' + ), + result + ); + } + } + } + } + } + + function testLogoWithBody() public { + for (uint8 b = 0; b <= uint8(type(Body.BodyVariants).max); b++) { + for (uint8 bc = 0; bc <= uint8(type(Body.BodyColors).max); bc++) { + for (uint8 l = 0; l <= uint8(type(Logo.LogoVariants).max); l++) { + for (uint8 lc = 0; lc <= uint8(type(Logo.LogoColors).max); lc++) { + uint256 seed = setVariant(b, Helpers.ComponentBytes.BODY) + + setColor(bc, Helpers.ComponentBytes.BODY) + + setVariant(l, Helpers.ComponentBytes.LOGO) + + setColor(lc, Helpers.ComponentBytes.LOGO); + string memory result = profileNFT.tryWithSeed(seed, false); + vm.writeFile( + string.concat( + dir, + 'logo/logo_b', + vm.toString(b), + '_bc', + vm.toString(bc), + '_l', + vm.toString(l), + '_lc', + vm.toString(lc), + '.svg' + ), + result + ); + } + } + } + } + } + + function testHeadwear() public { + for (uint8 v = 0; v <= uint8(type(Headwear.HeadwearVariants).max); v++) { + for (uint8 c = 0; c <= 7; c++) { + uint256 seed = setVariant(v, Helpers.ComponentBytes.HEADWEAR) + + setColor(c, Helpers.ComponentBytes.HEADWEAR); + string memory result = profileNFT.tryWithSeed(seed, false); + vm.writeFile( + string.concat(dir, 'headwear/headwear_v', vm.toString(v), '_c', vm.toString(c), '.svg'), + result + ); + } + } + for (uint8 v = 0; v <= uint8(type(Headwear.HeadwearVariants).max); v++) { + for (uint8 c = 0; c <= 7; c++) { + uint256 seed = setVariant(v, Helpers.ComponentBytes.HEADWEAR) + + setColor(c, Helpers.ComponentBytes.HEADWEAR); + string memory result = profileNFT.tryWithSeed(seed, true); + vm.writeFile( + string.concat(dir, 'headwear/headwear_v', vm.toString(v), '_c', vm.toString(c), '_onGold.svg'), + result + ); + } + } + // Icecream + for (uint8 c = 0; c <= 4; c++) { + uint256 seed = setVariant(69, Helpers.ComponentBytes.HEADWEAR) + + setColor(c, Helpers.ComponentBytes.HEADWEAR); + string memory result = profileNFT.tryWithSeed(seed, false); + vm.writeFile(string.concat(dir, 'headwear/headwear_v69', '_c', vm.toString(c), '.svg'), result); + } + for (uint8 c = 0; c <= 4; c++) { + uint256 seed = setVariant(69, Helpers.ComponentBytes.HEADWEAR) + + setColor(c, Helpers.ComponentBytes.HEADWEAR); + string memory result = profileNFT.tryWithSeed(seed, true); + vm.writeFile(string.concat(dir, 'headwear/headwear_v69', '_c', vm.toString(c), '_onGold.svg'), result); + } + } + + function testGoldProfiles1() public { + uint256 i; + for (i = 1; i < 500; i++) { + string memory result = profileNFT.tryProfile(i); + vm.writeFile(string.concat(dir, 'profiles_gold/profile_', vm.toString(i), '.svg'), result); + } + } + + function testGoldProfiles2() public { + uint256 i; + for (i = 500; i <= 1000; i++) { + string memory result = profileNFT.tryProfile(i); + vm.writeFile(string.concat(dir, 'profiles_gold/profile_', vm.toString(i), '.svg'), result); + } + } + + function testHowManyHaveIcecream() public view { + console.log('How many have icecream?'); + uint256 count; + for (uint256 i = 1; i < 130000; i++) { + uint256 seed = uint256(keccak256(abi.encodePacked(i))); + if (Helpers.getVariant(seed, Helpers.ComponentBytes.HEADWEAR) == 69) { + console.log(i); + count++; + } + } + console.log('Total: ', count); + } + + function testProfiles() public { + uint i = 1001; + string memory result = profileNFT.tryProfile(i); + vm.writeFile(string.concat(dir, 'profiles/profile_', vm.toString(i), '.svg'), result); + + for (i = 35000; i < 35500; i++) { + result = profileNFT.tryProfile(i); + vm.writeFile(string.concat(dir, 'profiles/profile_', vm.toString(i), '.svg'), result); + } + } + + function testFuzzProfiles() public { + for (uint256 i = 1; i < 1000; i++) { + uint256 profileId = uint256(keccak256(abi.encode(i))) % 10000000; + string memory result = profileNFT.tryProfile(profileId); + vm.writeFile(string.concat(dir, 'profiles_fuzz/profile_', vm.toString(profileId), '.svg'), result); + } + } + + // We take variants from the right bytes of the seed + function setVariant(uint256 newByte, Helpers.ComponentBytes componentByte) internal pure returns (uint256) { + return newByte << (uint8(componentByte) * 8); + } + + // We take colors from the left bytes of the seed + function setColor(uint256 newByte, Helpers.ComponentBytes componentByte) internal pure returns (uint256) { + return newByte << ((31 - uint8(componentByte)) * 8); + } +}