@@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
1010use serde_json:: Value ;
1111use std:: {
1212 collections:: { btree_map:: Entry , BTreeMap , BTreeSet } ,
13- ops :: { Deref , Not } ,
13+
1414} ;
1515
1616/// schemars [`Visitor`] that rewrites a [`Schema`] to conform to Kubernetes' "structural schema" rules
@@ -252,9 +252,10 @@ enum SingleOrVec<T> {
252252#[ cfg( test) ]
253253mod test {
254254 use assert_json_diff:: assert_json_eq;
255- use schemars:: { json_schema, schema_for, schema_for_value, JsonSchema } ;
256- use serde:: { de:: Expected , Deserialize , Serialize } ;
257- use serde_json:: json;
255+ use schemars:: { json_schema, schema_for, JsonSchema } ;
256+ use serde:: { Deserialize , Serialize } ;
257+
258+ use super :: * ;
258259
259260 /// A very simple enum with empty variants
260261 #[ derive( Serialize , Deserialize , Debug , Clone , JsonSchema ) ]
@@ -274,82 +275,103 @@ mod test {
274275
275276 #[ test]
276277 fn hoisting_a_schema ( ) {
277- let incoming = json_schema ! (
278- {
279- "$schema" : "https://json-schema.org/draft/2020-12/schema" ,
280- "description" : "A very simple enum with empty variants" ,
281- "oneOf" : [
282- {
283- "enum" : [
284- "C" ,
285- "D"
278+ let schemars_schema = schema_for ! ( NormalEnum ) ;
279+ let mut kube_schema: crate :: schema:: Schema =
280+ schemars_schema_to_kube_schema ( schemars_schema. clone ( ) ) . unwrap ( ) ;
281+
282+ assert_json_eq ! (
283+ schemars_schema,
284+ json_schema!(
285+ {
286+ "$schema" : "https://json-schema.org/draft/2020-12/schema" ,
287+ "description" : "A very simple enum with empty variants" ,
288+ "oneOf" : [
289+ {
290+ "enum" : [
291+ "C" ,
292+ "D"
293+ ] ,
294+ "type" : "string"
295+ } ,
296+ {
297+ "const" : "A" ,
298+ "description" : "First variant" ,
299+ "type" : "string"
300+ } ,
301+ {
302+ "const" : "B" ,
303+ "description" : "Second variant" ,
304+ "type" : "string"
305+ }
286306 ] ,
287- "type" : "string"
288- } ,
289- {
290- "const" : "A" ,
291- "description" : "First variant" ,
292- "type" : "string"
293- } ,
294- {
295- "const" : "B" ,
296- "description" : "Second variant" ,
297- "type" : "string"
307+ "title" : "NormalEnum"
298308 }
299- ] ,
300- "title" : "NormalEnum"
301- }
309+ )
302310 ) ;
303-
304- // Initial check that the text schema above is correct for NormalEnum
305- assert_json_eq ! ( schema_for! ( NormalEnum ) , incoming ) ;
306-
307- let expected = json_schema ! (
308- {
309- "$schema ": "https://json-schema.org/draft/2020-12/schema " ,
310- "description" : "A very simple enum with empty variants ",
311- "type ": "string" ,
312- "enum" : [
313- "C ",
314- "D ",
315- "A" ,
316- "B"
317- ] ,
318- "title" : "NormalEnum"
319- }
311+ hoist_one_of_enum ( & mut kube_schema ) ;
312+ assert_json_eq ! (
313+ kube_schema ,
314+ json_schema! (
315+ {
316+ "$schema" : "https://json-schema.org/draft/2020-12/schema" ,
317+ "description ": "A very simple enum with empty variants " ,
318+ "type" : "string ",
319+ "enum ": [
320+ "C" ,
321+ "D ",
322+ "A ",
323+ "B"
324+ ] ,
325+ "title" : "NormalEnum"
326+ }
327+ )
320328 ) ;
321-
322- // let actual = hoist
323-
324- // assert_json_eq!(expected, actual);
325329 }
326330}
327331
328- fn hoist_one_of_enum ( incoming : Schema ) -> Schema {
329- let Schema :: Object ( SchemaObject {
332+ #[ cfg( test) ]
333+ fn schemars_schema_to_kube_schema ( incoming : schemars:: Schema ) -> Result < Schema , serde_json:: Error > {
334+ serde_json:: from_value ( incoming. to_value ( ) )
335+ }
336+
337+ #[ cfg( test) ]
338+ fn hoist_one_of_enum ( schema : & mut Schema ) {
339+ if let Schema :: Object ( SchemaObject {
330340 subschemas : Some ( subschemas) ,
341+ instance_type : object_type,
342+ enum_values : object_ebum,
331343 ..
332- } ) = & incoming
333- else {
334- return incoming;
335- } ;
336-
337- let SubschemaValidation {
344+ } ) = schema && let SubschemaValidation {
338345 one_of : Some ( one_of) , ..
339- } = subschemas. deref ( )
340- else {
341- return incoming;
342- } ;
343-
344- if one_of. is_empty ( ) {
345- return incoming;
346- }
347-
348- // now the meat. Need to get the oneOf variants up into `enum`
349- // panic if the types differ
346+ } = & * * subschemas
347+ && !one_of. is_empty ( )
348+ {
349+ let mut types = one_of. iter ( ) . map ( |obj| match obj {
350+ Schema :: Object ( SchemaObject { instance_type : Some ( type_) , ..} ) => type_,
351+ Schema :: Object ( _) => panic ! ( "oneOf variants need to define a type!: {obj:?}" ) ,
352+ Schema :: Bool ( _) => panic ! ( "oneOf variants can not be of type boolean" ) ,
353+ } ) ;
354+ let enums = one_of. iter ( ) . flat_map ( |obj| match obj {
355+ Schema :: Object ( SchemaObject { enum_values : Some ( enum_) , ..} ) => enum_. clone ( ) ,
356+ Schema :: Object ( SchemaObject { other, ..} ) => match other. get ( "const" ) {
357+ Some ( const_) => vec ! [ const_. clone( ) ] ,
358+ None => panic ! ( "oneOf variant did not provide \" enum\" or \" const\" : {obj:?}" ) ,
359+ } ,
360+ Schema :: Bool ( _) => panic ! ( "oneOf variants can not be of type boolean" ) ,
361+ } ) ;
362+
363+ let first_type = types
364+ . next ( )
365+ . expect ( "oneOf must have at least one variant - we already checked that" ) ;
366+ if types. any ( |t| t != first_type) {
367+ panic ! ( "All oneOf variants must have the same type" ) ;
368+ }
350369
370+ * object_type = Some ( first_type. clone ( ) ) ;
371+ * object_ebum = Some ( enums. collect ( ) ) ;
372+ subschemas. one_of = None ;
351373
352- todo ! ( "finish it" )
374+ }
353375}
354376
355377impl Transform for StructuralSchemaRewriter {
0 commit comments