doc_examples.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // SPDX-License-Identifier: Apache-2.0
  2. use rayon::prelude::*;
  3. use solang::{
  4. codegen::{codegen, OptimizationLevel, Options},
  5. file_resolver::FileResolver,
  6. sema::diagnostics::Diagnostics,
  7. Target,
  8. };
  9. use std::{
  10. ffi::OsStr,
  11. fs::{read_dir, read_to_string},
  12. };
  13. /// Populates a file resolver with all imports that could be used by some example.
  14. fn file_resolver(target: Target) -> FileResolver {
  15. let mut result = FileResolver::new();
  16. result.set_file_contents(
  17. "docs/examples/user.sol",
  18. r##"
  19. struct User { string name; uint count; }
  20. function clear_count(User memory user) {
  21. user.count = 0;
  22. }
  23. using {clear_count} for User global;"##
  24. .into(),
  25. );
  26. if let Target::Solana = target {
  27. result.set_file_contents(
  28. "docs/examples/solana/bobcat.sol",
  29. r##"
  30. anchor_anchor constant bobcat = anchor_anchor(address'z7FbDfQDfucxJz5o8jrGLgvSbdoeSqX5VrxBb5TVjHq');
  31. interface anchor_anchor {
  32. @selector([0xaf, 0xaf, 0x6d, 0x1f, 0x0d, 0x98, 0x9b, 0xed])
  33. function pounce() view external returns(int64);
  34. }"##.into(),
  35. );
  36. }
  37. result
  38. }
  39. /// Returns a list of all `.sol` files in the given `dir` path.
  40. fn get_source_files(dir: &str) -> Vec<String> {
  41. read_dir(dir)
  42. .unwrap()
  43. .into_iter()
  44. .filter_map(|entry| {
  45. let e = entry.unwrap();
  46. if let (true, Some(ext)) = (e.path().is_file(), e.path().extension()) {
  47. if ext == "sol" {
  48. return Some(e.path().display().to_string());
  49. }
  50. }
  51. None
  52. })
  53. .collect()
  54. }
  55. /// Attempts to compile the file at `path` for the `target`, returning the diagnostics on fail.
  56. fn try_compile(path: &str, target: Target) -> Result<(), Diagnostics> {
  57. let mut cache = file_resolver(target);
  58. cache.set_file_contents(path, read_to_string(path).unwrap());
  59. let mut ns = solang::parse_and_resolve(OsStr::new(path), &mut cache, target);
  60. if ns.diagnostics.any_errors() {
  61. return Err(ns.diagnostics);
  62. }
  63. // Codegen should work too
  64. codegen(
  65. &mut ns,
  66. &Options {
  67. dead_storage: true,
  68. constant_folding: true,
  69. strength_reduce: true,
  70. vector_to_slice: true,
  71. math_overflow_check: true,
  72. common_subexpression_elimination: true,
  73. opt_level: OptimizationLevel::Default,
  74. ..Default::default()
  75. },
  76. );
  77. Ok(())
  78. }
  79. /// Assert no compilation errors for all `.sol` files found in `dir`.
  80. fn assert_compile(dir: &str, target: Target) {
  81. let errors = get_source_files(dir)
  82. .par_iter()
  83. .filter_map(|path| try_compile(path, target).err().map(|msg| (path, msg)))
  84. .map(|(path, msg)| println!("{} failed: {:#?}", path, msg))
  85. .count();
  86. assert_eq!(0, errors);
  87. }
  88. #[test]
  89. fn substrate_general() {
  90. assert_compile("examples", Target::default_substrate());
  91. assert_compile("docs/examples/", Target::default_substrate());
  92. }
  93. #[test]
  94. fn substrate_specific() {
  95. assert_compile("docs/examples/substrate/", Target::default_substrate());
  96. }
  97. #[test]
  98. fn solana_general() {
  99. assert_compile("examples", Target::Solana);
  100. assert_compile("docs/examples/", Target::Solana);
  101. }
  102. #[test]
  103. fn solana_specific() {
  104. assert_compile("docs/examples/solana", Target::Solana);
  105. }